mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-14 20:47:38 +00:00
Merge tag 'upstream/0.21.0'
* tag 'upstream/0.21.0': (723 commits) test: remove assembla clone test test: use read-only account http: fix typo in credentials logic ssl: init everything all the time ssl: init also without threads ssl: cargo-cult thread safety ssl: use locking remote: update documentation netops: init OpenSSL once under lock revwalk: more sensible array handling pathspec: use C guards in header treebuilder: insert sorted remote: fix rename docs Bump version to 0.21.0 Change SOVERSION at API breaks React to review feedback Win32: Fix object::cache::threadmania test on x64 Win32: Fix diff::workdir::submodules test #2361 Win32: Fix failing clone_mirror test remote: don't free the remote on delete ...
This commit is contained in:
commit
da6fa9054a
26
.travis.yml
26
.travis.yml
@ -3,23 +3,39 @@
|
||||
|
||||
language: c
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
|
||||
# Settings to try
|
||||
env:
|
||||
global:
|
||||
- secure: "YnhS+8n6B+uoyaYfaJ3Lei7cSJqHDPiKJCKFIF2c87YDfmCvAJke8QtE7IzjYDs7UFkTCM4ox+ph2bERUrxZbSCyEkHdjIZpKuMJfYWja/jgMqTMxdyOH9y8JLFbZsSXDIXDwqBlC6vVyl1fP90M35wuWcNTs6tctfVWVofEFbs="
|
||||
matrix:
|
||||
- OPTIONS="-DTHREADSAFE=ON -DCMAKE_BUILD_TYPE=Release"
|
||||
- OPTIONS="-DBUILD_CLAR=ON -DBUILD_EXAMPLES=ON"
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
exclude:
|
||||
- os: osx
|
||||
compiler: gcc
|
||||
include:
|
||||
- compiler: i586-mingw32msvc-gcc
|
||||
env: OPTIONS="-DBUILD_CLAR=OFF -DWIN32=ON -DMINGW=ON"
|
||||
env: OPTIONS="-DBUILD_CLAR=OFF -DWIN32=ON -DMINGW=ON -DUSE_SSH=OFF"
|
||||
os: linux
|
||||
- compiler: gcc
|
||||
env: COVERITY=1
|
||||
os: linux
|
||||
allow_failures:
|
||||
- env: COVERITY=1
|
||||
|
||||
install:
|
||||
- sudo apt-get -qq update
|
||||
- sudo apt-get -qq install cmake libssh2-1-dev openssh-client openssh-server
|
||||
- ./script/install-deps-${TRAVIS_OS_NAME}.sh
|
||||
|
||||
# Run the Build script and tests
|
||||
script:
|
||||
@ -27,8 +43,8 @@ script:
|
||||
|
||||
# Run Tests
|
||||
after_success:
|
||||
- sudo apt-get -qq install valgrind
|
||||
- valgrind --leak-check=full --show-reachable=yes --suppressions=./libgit2_clar.supp _build/libgit2_clar -ionline
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -qq install valgrind; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then valgrind --leak-check=full --show-reachable=yes --suppressions=./libgit2_clar.supp _build/libgit2_clar -ionline; fi
|
||||
|
||||
# Only watch the development branch
|
||||
branches:
|
||||
|
2
AUTHORS
2
AUTHORS
@ -6,6 +6,7 @@ Alexei Sholik
|
||||
Andreas Ericsson
|
||||
Anton "antong" Gyllenberg
|
||||
Ankur Sethi
|
||||
Arthur Schreiber
|
||||
Ben Noordhuis
|
||||
Ben Straub
|
||||
Benjamin C Meyer
|
||||
@ -25,6 +26,7 @@ Florian Forster
|
||||
Holger Weiss
|
||||
Ingmar Vanhassel
|
||||
J. David Ibáñez
|
||||
Jacques Germishuys
|
||||
Jakob Pfender
|
||||
Jason Penny
|
||||
Jason R. McNeil
|
||||
|
100
CMakeLists.txt
100
CMakeLists.txt
@ -15,7 +15,10 @@ PROJECT(libgit2 C)
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
|
||||
|
||||
# Add find modules to the path
|
||||
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
|
||||
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/")
|
||||
|
||||
INCLUDE(CheckLibraryExists)
|
||||
INCLUDE(AddCFlagIfSupported)
|
||||
|
||||
# Build options
|
||||
#
|
||||
@ -33,8 +36,9 @@ OPTION( ANDROID "Build for android NDK" OFF )
|
||||
|
||||
OPTION( USE_ICONV "Link with and use iconv library" OFF )
|
||||
OPTION( USE_SSH "Link with libssh to enable SSH support" ON )
|
||||
OPTION( VALGRIND "Configure build for valgrind" OFF )
|
||||
|
||||
IF(APPLE)
|
||||
IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
SET( USE_ICONV ON )
|
||||
ENDIF()
|
||||
|
||||
@ -54,6 +58,10 @@ IF(MSVC)
|
||||
# By default, libgit2 is built with WinHTTP. To use the built-in
|
||||
# HTTP transport, invoke CMake with the "-DWINHTTP=OFF" argument.
|
||||
OPTION( WINHTTP "Use Win32 WinHTTP routines" ON )
|
||||
|
||||
ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS)
|
||||
ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE)
|
||||
ADD_DEFINITIONS(-D_CRT_NONSTDC_NO_DEPRECATE)
|
||||
ENDIF()
|
||||
|
||||
# This variable will contain the libraries we need to put into
|
||||
@ -77,17 +85,13 @@ FUNCTION(TARGET_OS_LIBRARIES target)
|
||||
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
|
||||
TARGET_LINK_LIBRARIES(${target} socket nsl)
|
||||
SET(LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS} -lsocket -lnsl" PARENT_SCOPE)
|
||||
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
ENDIF()
|
||||
CHECK_LIBRARY_EXISTS(rt clock_gettime "time.h" NEED_LIBRT)
|
||||
IF(NEED_LIBRT)
|
||||
TARGET_LINK_LIBRARIES(${target} rt)
|
||||
SET(LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS} -lrt" PARENT_SCOPE)
|
||||
ENDIF()
|
||||
|
||||
IF(USE_ICONV)
|
||||
TARGET_LINK_LIBRARIES(${target} iconv)
|
||||
ADD_DEFINITIONS(-DGIT_USE_ICONV)
|
||||
SET(LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS} -liconv" PARENT_SCOPE)
|
||||
ENDIF()
|
||||
|
||||
IF(THREADSAFE)
|
||||
TARGET_LINK_LIBRARIES(${target} ${CMAKE_THREAD_LIBS_INIT})
|
||||
ENDIF()
|
||||
@ -123,6 +127,9 @@ STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_V
|
||||
STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_VERSION_REV "${GIT2_HEADER}")
|
||||
SET(LIBGIT2_VERSION_STRING "${LIBGIT2_VERSION_MAJOR}.${LIBGIT2_VERSION_MINOR}.${LIBGIT2_VERSION_REV}")
|
||||
|
||||
FILE(STRINGS "include/git2/version.h" GIT2_HEADER_SOVERSION REGEX "^#define LIBGIT2_SOVERSION [0-9]+$")
|
||||
STRING(REGEX REPLACE "^.*LIBGIT2_SOVERSION ([0-9]+)$" "\\1" LIBGIT2_SOVERSION "${GIT2_HEADER_SOVERSION}")
|
||||
|
||||
# Find required dependencies
|
||||
INCLUDE_DIRECTORIES(src include)
|
||||
|
||||
@ -135,13 +142,13 @@ ELSE ()
|
||||
FIND_PACKAGE(OpenSSL)
|
||||
ENDIF ()
|
||||
|
||||
FIND_PACKAGE(HTTP_Parser QUIET)
|
||||
FIND_PACKAGE(HTTP_Parser)
|
||||
IF (HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2)
|
||||
INCLUDE_DIRECTORIES(${HTTP_PARSER_INCLUDE_DIRS})
|
||||
LINK_LIBRARIES(${HTTP_PARSER_LIBRARIES})
|
||||
SET(LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS} -lhttp_parser")
|
||||
ELSE()
|
||||
MESSAGE("http-parser was not found or is too old; using bundled 3rd-party sources.")
|
||||
MESSAGE(STATUS "http-parser was not found or is too old; using bundled 3rd-party sources.")
|
||||
INCLUDE_DIRECTORIES(deps/http-parser)
|
||||
FILE(GLOB SRC_HTTP deps/http-parser/*.c deps/http-parser/*.h)
|
||||
ENDIF()
|
||||
@ -153,7 +160,11 @@ IF (WIN32 AND NOT MINGW AND NOT SHA1_TYPE STREQUAL "builtin")
|
||||
FILE(GLOB SRC_SHA1 src/hash/hash_win32.c)
|
||||
ELSEIF (OPENSSL_FOUND AND NOT SHA1_TYPE STREQUAL "builtin")
|
||||
ADD_DEFINITIONS(-DOPENSSL_SHA1)
|
||||
SET(LIBGIT2_PC_REQUIRES "${LIBGIT2_PC_REQUIRES} openssl")
|
||||
IF (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
|
||||
SET(LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS} -lssl")
|
||||
ELSE()
|
||||
SET(LIBGIT2_PC_REQUIRES "${LIBGIT2_PC_REQUIRES} openssl")
|
||||
ENDIF ()
|
||||
ELSE()
|
||||
FILE(GLOB SRC_SHA1 src/hash/hash_generic.c)
|
||||
ENDIF()
|
||||
@ -164,34 +175,31 @@ IF (ENABLE_TRACE STREQUAL "ON")
|
||||
ENDIF()
|
||||
|
||||
# Include POSIX regex when it is required
|
||||
IF(WIN32 OR AMIGA OR ANDROID)
|
||||
IF(WIN32 OR AMIGA OR ANDROID OR CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
|
||||
INCLUDE_DIRECTORIES(deps/regex)
|
||||
SET(SRC_REGEX deps/regex/regex.c)
|
||||
ENDIF()
|
||||
|
||||
# Optional external dependency: zlib
|
||||
# It's optional, but FIND_PACKAGE gives a warning that looks more like an
|
||||
# error.
|
||||
FIND_PACKAGE(ZLIB QUIET)
|
||||
FIND_PACKAGE(ZLIB)
|
||||
IF (ZLIB_FOUND)
|
||||
INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIRS})
|
||||
LINK_LIBRARIES(${ZLIB_LIBRARIES})
|
||||
IF(APPLE)
|
||||
IF(APPLE OR CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
|
||||
SET(LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS} -lz")
|
||||
ELSE()
|
||||
SET(LIBGIT2_PC_REQUIRES "${LIBGIT2_PC_REQUIRES} zlib")
|
||||
ENDIF()
|
||||
# Fake the message CMake would have shown
|
||||
MESSAGE("-- Found zlib: ${ZLIB_LIBRARY}")
|
||||
ELSE()
|
||||
MESSAGE( "zlib was not found; using bundled 3rd-party sources." )
|
||||
MESSAGE(STATUS "zlib was not found; using bundled 3rd-party sources." )
|
||||
INCLUDE_DIRECTORIES(deps/zlib)
|
||||
ADD_DEFINITIONS(-DNO_VIZ -DSTDC -DNO_GZIP)
|
||||
FILE(GLOB SRC_ZLIB deps/zlib/*.c deps/zlib/*.h)
|
||||
ENDIF()
|
||||
|
||||
IF (USE_SSH AND NOT MINGW)
|
||||
FIND_PACKAGE(LIBSSH2 QUIET)
|
||||
# Optional external dependency: libssh2
|
||||
IF (USE_SSH)
|
||||
FIND_PACKAGE(LIBSSH2)
|
||||
ENDIF()
|
||||
IF (LIBSSH2_FOUND)
|
||||
ADD_DEFINITIONS(-DGIT_SSH)
|
||||
@ -200,6 +208,15 @@ IF (LIBSSH2_FOUND)
|
||||
SET(SSH_LIBRARIES ${LIBSSH2_LIBRARIES})
|
||||
ENDIF()
|
||||
|
||||
# Optional external dependency: iconv
|
||||
IF (USE_ICONV)
|
||||
FIND_PACKAGE(Iconv)
|
||||
ENDIF()
|
||||
IF (ICONV_FOUND)
|
||||
ADD_DEFINITIONS(-DGIT_USE_ICONV)
|
||||
INCLUDE_DIRECTORIES(${ICONV_INCLUDE_DIR})
|
||||
SET(LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS} ${ICONV_LIBRARIES}")
|
||||
ENDIF()
|
||||
|
||||
# Platform specific compilation flags
|
||||
IF (MSVC)
|
||||
@ -274,7 +291,11 @@ IF (MSVC)
|
||||
# Precompiled headers
|
||||
|
||||
ELSE ()
|
||||
SET(CMAKE_C_FLAGS "-D_GNU_SOURCE -Wall -Wextra -Wno-missing-field-initializers -Wstrict-aliasing=2 -Wstrict-prototypes ${CMAKE_C_FLAGS}")
|
||||
SET(CMAKE_C_FLAGS "-D_GNU_SOURCE -Wall -Wextra ${CMAKE_C_FLAGS}")
|
||||
|
||||
IF (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
|
||||
SET(CMAKE_C_FLAGS "-std=c99 -D_POSIX_C_SOURCE=200112L -D__EXTENSIONS__ -D_POSIX_PTHREAD_SEMANTICS ${CMAKE_C_FLAGS}")
|
||||
ENDIF()
|
||||
|
||||
IF (WIN32 AND NOT CYGWIN)
|
||||
SET(CMAKE_C_FLAGS_DEBUG "-D_DEBUG")
|
||||
@ -288,11 +309,22 @@ ELSE ()
|
||||
ADD_DEFINITIONS(-D__USE_MINGW_ANSI_STDIO=1)
|
||||
|
||||
ELSEIF (BUILD_SHARED_LIBS)
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden -fPIC")
|
||||
ADD_C_FLAG_IF_SUPPORTED(-fvisibility=hidden)
|
||||
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
|
||||
ENDIF ()
|
||||
|
||||
ADD_C_FLAG_IF_SUPPORTED(-Wno-missing-field-initializers)
|
||||
ADD_C_FLAG_IF_SUPPORTED(-Wstrict-aliasing=2)
|
||||
ADD_C_FLAG_IF_SUPPORTED(-Wstrict-prototypes)
|
||||
ADD_C_FLAG_IF_SUPPORTED(-Wdeclaration-after-statement)
|
||||
ADD_C_FLAG_IF_SUPPORTED(-Wno-unused-const-variable)
|
||||
ADD_C_FLAG_IF_SUPPORTED(-Wno-unused-function)
|
||||
|
||||
IF (APPLE) # Apple deprecated OpenSSL
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations")
|
||||
ENDIF ()
|
||||
ADD_C_FLAG_IF_SUPPORTED(-Wno-deprecated-declarations)
|
||||
ENDIF()
|
||||
|
||||
IF (PROFILE)
|
||||
SET(CMAKE_C_FLAGS "-pg ${CMAKE_C_FLAGS}")
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "-pg ${CMAKE_EXE_LINKER_FLAGS}")
|
||||
@ -317,7 +349,7 @@ ENDIF()
|
||||
|
||||
IF (THREADSAFE)
|
||||
IF (NOT WIN32)
|
||||
find_package(Threads REQUIRED)
|
||||
FIND_PACKAGE(Threads REQUIRED)
|
||||
ENDIF()
|
||||
|
||||
ADD_DEFINITIONS(-DGIT_THREADS)
|
||||
@ -333,9 +365,11 @@ IF (WIN32 AND NOT CYGWIN)
|
||||
ADD_DEFINITIONS(-DWIN32 -D_WIN32_WINNT=0x0501)
|
||||
FILE(GLOB SRC_OS src/win32/*.c src/win32/*.h)
|
||||
ELSEIF (AMIGA)
|
||||
ADD_DEFINITIONS(-DNO_ADDRINFO -DNO_READDIR_R)
|
||||
FILE(GLOB SRC_OS src/amiga/*.c src/amiga/*.h)
|
||||
ADD_DEFINITIONS(-DNO_ADDRINFO -DNO_READDIR_R -DNO_MMAP)
|
||||
ELSE()
|
||||
IF (VALGRIND)
|
||||
ADD_DEFINITIONS(-DNO_MMAP)
|
||||
ENDIF()
|
||||
FILE(GLOB SRC_OS src/unix/*.c src/unix/*.h)
|
||||
ENDIF()
|
||||
FILE(GLOB SRC_GIT2 src/*.c src/*.h src/transports/*.c src/transports/*.h src/xdiff/*.c src/xdiff/*.h)
|
||||
@ -346,13 +380,14 @@ IF (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
ELSEIF (CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
ADD_DEFINITIONS(-DGIT_ARCH_32)
|
||||
ELSE()
|
||||
message(FATAL_ERROR "Unsupported architecture")
|
||||
MESSAGE(FATAL_ERROR "Unsupported architecture")
|
||||
ENDIF()
|
||||
|
||||
# Compile and link libgit2
|
||||
ADD_LIBRARY(git2 ${SRC_H} ${SRC_GIT2} ${SRC_OS} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX} ${SRC_SHA1} ${WIN_RC})
|
||||
TARGET_LINK_LIBRARIES(git2 ${SSL_LIBRARIES})
|
||||
TARGET_LINK_LIBRARIES(git2 ${SSH_LIBRARIES})
|
||||
TARGET_LINK_LIBRARIES(git2 ${ICONV_LIBRARIES})
|
||||
TARGET_OS_LIBRARIES(git2)
|
||||
|
||||
# Workaround for Cmake bug #0011240 (see http://public.kitware.com/Bug/view.php?id=11240)
|
||||
@ -365,7 +400,7 @@ MSVC_SPLIT_SOURCES(git2)
|
||||
|
||||
IF (SONAME)
|
||||
SET_TARGET_PROPERTIES(git2 PROPERTIES VERSION ${LIBGIT2_VERSION_STRING})
|
||||
SET_TARGET_PROPERTIES(git2 PROPERTIES SOVERSION ${LIBGIT2_VERSION_MAJOR})
|
||||
SET_TARGET_PROPERTIES(git2 PROPERTIES SOVERSION ${LIBGIT2_SOVERSION})
|
||||
IF (LIBGIT2_FILENAME)
|
||||
ADD_DEFINITIONS(-DLIBGIT2_FILENAME=\"${LIBGIT2_FILENAME}\")
|
||||
SET_TARGET_PROPERTIES(git2 PROPERTIES OUTPUT_NAME ${LIBGIT2_FILENAME})
|
||||
@ -418,6 +453,7 @@ IF (BUILD_CLAR)
|
||||
|
||||
TARGET_LINK_LIBRARIES(libgit2_clar ${SSL_LIBRARIES})
|
||||
TARGET_LINK_LIBRARIES(libgit2_clar ${SSH_LIBRARIES})
|
||||
TARGET_LINK_LIBRARIES(libgit2_clar ${ICONV_LIBRARIES})
|
||||
TARGET_OS_LIBRARIES(libgit2_clar)
|
||||
MSVC_SPLIT_SOURCES(libgit2_clar)
|
||||
|
||||
@ -433,7 +469,7 @@ ENDIF ()
|
||||
IF (TAGS)
|
||||
FIND_PROGRAM(CTAGS ctags)
|
||||
IF (NOT CTAGS)
|
||||
message(FATAL_ERROR "Could not find ctags command")
|
||||
MESSAGE(FATAL_ERROR "Could not find ctags command")
|
||||
ENDIF ()
|
||||
|
||||
FILE(GLOB_RECURSE SRC_ALL *.[ch])
|
||||
|
@ -5,9 +5,13 @@ your help.
|
||||
|
||||
## Licensing
|
||||
|
||||
By contributing to libgit2, you agree to release your contribution under the terms of the license.
|
||||
For code under `examples`, this is governed by the [CC0 Public Domain Dedication](examples/COPYING).
|
||||
All other code is released under the [GPL v2 with linking exception](COPYING).
|
||||
By contributing to libgit2, you agree to release your contribution under
|
||||
the terms of the license. Except for the `examples` directory, all code
|
||||
is released under the [GPL v2 with linking exception](COPYING).
|
||||
|
||||
The `examples` code is governed by the
|
||||
[CC0 Public Domain Dedication](examples/COPYING), so that you may copy
|
||||
from them into your own application.
|
||||
|
||||
## Discussion & Chat
|
||||
|
||||
@ -76,15 +80,19 @@ you're porting code *from* to see what you need to do. As a general rule,
|
||||
MIT and BSD (3-clause) licenses are typically no problem. Apache 2.0
|
||||
license typically doesn't work due to GPL incompatibility.
|
||||
|
||||
If you are pulling in code from core Git, another project or code you've pulled from
|
||||
a forum / Stack Overflow then please flag this in your PR and also make sure you've
|
||||
given proper credit to the original author in the code snippet.
|
||||
If you are pulling in code from core Git, another project or code you've
|
||||
pulled from a forum / Stack Overflow then please flag this in your PR and
|
||||
also make sure you've given proper credit to the original author in the
|
||||
code snippet.
|
||||
|
||||
## Style Guide
|
||||
|
||||
`libgit2` is written in [ANSI C](http://en.wikipedia.org/wiki/ANSI_C)
|
||||
(a.k.a. C89) with some specific conventions for function and type naming,
|
||||
code formatting, and testing.
|
||||
The public API of `libgit2` is [ANSI C](http://en.wikipedia.org/wiki/ANSI_C)
|
||||
(a.k.a. C89) compatible. Internally, `libgit2` is written using a portable
|
||||
subset of C99 - in order to compile with GCC, Clang, MSVC, etc., we keep
|
||||
local variable declarations at the tops of blocks only and avoid `//` style
|
||||
comments. Additionally, `libgit2` follows some extra conventions for
|
||||
function and type naming, code formatting, and testing.
|
||||
|
||||
We like to keep the source code consistent and easy to read. Maintaining
|
||||
this takes some discipline, but it's been more than worth it. Take a look
|
||||
@ -93,22 +101,4 @@ at the
|
||||
|
||||
## Starter Projects
|
||||
|
||||
So, you want to start helping out with `libgit2`? That's fantastic? We
|
||||
welcome contributions and we promise we'll try to be nice.
|
||||
|
||||
If you want to jump in, you can look at our issues list to see if there
|
||||
are any unresolved issues to jump in on. Also, here is a list of some
|
||||
smaller project ideas that could help you become familiar with the code
|
||||
base and make a nice first step:
|
||||
|
||||
* Convert a `git_*modulename*_foreach()` callback-based iteration API
|
||||
into a `git_*modulename*_iterator` object with a create/advance style
|
||||
of API. This helps folks writing language bindings and usually isn't
|
||||
too complicated.
|
||||
* Write a new `examples/` program that mirrors a particular core git
|
||||
command. (See `examples/diff.c` for example.) This lets you (and us)
|
||||
easily exercise a particular facet of the API and measure compatability
|
||||
and feature parity with core git.
|
||||
* Submit a PR to clarify documentation! While we do try to document all of
|
||||
the APIs, your fresh eyes on the documentation will find areas that are
|
||||
confusing much more easily.
|
||||
See our [projects list](https://github.com/libgit2/libgit2/blob/development/PROJECTS.md).
|
||||
|
@ -6,14 +6,18 @@ guidelines that should help with that.
|
||||
## Compatibility
|
||||
|
||||
`libgit2` runs on many different platforms with many different compilers.
|
||||
It is written in [ANSI C](http://en.wikipedia.org/wiki/ANSI_C) (a.k.a. C89)
|
||||
with some specific standards for function and type naming, code formatting,
|
||||
and testing.
|
||||
|
||||
We try to avoid more recent extensions to maximize portability. We also, to
|
||||
the greatest extent possible, try to avoid lots of `#ifdef`s inside the core
|
||||
code base. This is somewhat unavoidable, but since it can really hamper
|
||||
maintainability, we keep it to a minimum.
|
||||
The public API of `libgit2` is [ANSI C](http://en.wikipedia.org/wiki/ANSI_C)
|
||||
(a.k.a. C89) compatible.
|
||||
|
||||
Internally, `libgit2` is written using a portable subset of C99 - in order
|
||||
to maximize compatibility (e.g. with MSVC) we avoid certain C99
|
||||
extensions. Specifically, we keep local variable declarations at the tops
|
||||
of blocks only and we avoid `//` style comments.
|
||||
|
||||
Also, to the greatest extent possible, we try to avoid lots of `#ifdef`s
|
||||
inside the core code base. This is somewhat unavoidable, but since it can
|
||||
really hamper maintainability, we keep it to a minimum.
|
||||
|
||||
## Match Surrounding Code
|
||||
|
||||
@ -209,6 +213,9 @@ All inlined functions must be declared as:
|
||||
GIT_INLINE(result_type) git_modulename_functionname(arg_list);
|
||||
```
|
||||
|
||||
`GIT_INLINE` (or `inline`) should not be used in public headers in order
|
||||
to preserve ANSI C compatibility.
|
||||
|
||||
## Tests
|
||||
|
||||
`libgit2` uses the [clar](https://github.com/vmg/clar) testing framework.
|
||||
|
75
COPYING
75
COPYING
@ -388,19 +388,7 @@ Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
The priority queue implementation is based on code licensed under the
|
||||
Apache 2.0 license:
|
||||
|
||||
Copyright 2010 Volkan Yazıcı <volkan.yazici@gmail.com>
|
||||
Copyright 2006-2010 The Apache Software Foundation
|
||||
|
||||
The full text of the Apache 2.0 license is available at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
The Clay framework is licensed under the MIT license:
|
||||
The Clar framework is licensed under the MIT license:
|
||||
|
||||
Copyright (C) 2011 by Vicent Marti
|
||||
|
||||
@ -930,64 +918,3 @@ necessary. Here is a sample; alter the names:
|
||||
That's all there is to it!
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Portions of src/win32/posix_w32.c are derrived from link_win32.c in PHP:
|
||||
|
||||
--------------------------------------------------------------------
|
||||
The PHP License, version 3.01
|
||||
Copyright (c) 1999 - 2012 The PHP Group. All rights reserved.
|
||||
--------------------------------------------------------------------
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, is permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
3. The name "PHP" must not be used to endorse or promote products
|
||||
derived from this software without prior written permission. For
|
||||
written permission, please contact group@php.net.
|
||||
|
||||
4. Products derived from this software may not be called "PHP", nor
|
||||
may "PHP" appear in their name, without prior written permission
|
||||
from group@php.net. You may indicate that your software works in
|
||||
conjunction with PHP by saying "Foo for PHP" instead of calling
|
||||
it "PHP Foo" or "phpfoo"
|
||||
|
||||
5. The PHP Group may publish revised and/or new versions of the
|
||||
license from time to time. Each version will be given a
|
||||
distinguishing version number.
|
||||
Once covered code has been published under a particular version
|
||||
of the license, you may always continue to use it under the terms
|
||||
of that version. You may also choose to use such covered code
|
||||
under the terms of any subsequent version of the license
|
||||
published by the PHP Group. No one other than the PHP Group has
|
||||
the right to modify the terms applicable to covered code created
|
||||
under this License.
|
||||
|
||||
6. Redistributions of any form whatsoever must retain the following
|
||||
acknowledgment:
|
||||
"This product includes PHP software, freely available from
|
||||
<http://www.php.net/software/>".
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
|
||||
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
|
||||
DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
|
85
PROJECTS.md
Normal file
85
PROJECTS.md
Normal file
@ -0,0 +1,85 @@
|
||||
Projects For LibGit2
|
||||
====================
|
||||
|
||||
So, you want to start helping out with `libgit2`? That's fantastic! We
|
||||
welcome contributions and we promise we'll try to be nice.
|
||||
|
||||
This is a list of libgit2 related projects that new contributors can take
|
||||
on. It includes a number of good starter projects and well as some larger
|
||||
ideas that no one is actively working on.
|
||||
|
||||
## Before You Start
|
||||
|
||||
Please start by reading the README.md, CONTRIBUTING.md, and CONVENTIONS.md
|
||||
files before diving into one of these projects. Those will explain our
|
||||
work flow and coding conventions to help ensure that your work will be
|
||||
easily integrated into libgit2.
|
||||
|
||||
Next, work through the build instructions and make sure you can clone the
|
||||
repository, compile it, and run the tests successfully. That will make
|
||||
sure that your development environment is set up correctly and you are
|
||||
ready to start on libgit2 development.
|
||||
|
||||
## Starter Projects
|
||||
|
||||
These are good small projects to get started with libgit2.
|
||||
|
||||
* Look at the `examples/` programs, find an existing one that mirrors a
|
||||
core Git command and add a missing command-line option. There are many
|
||||
gaps right now and this helps demonstrate how to use the library. Here
|
||||
are some specific ideas:
|
||||
* Fix the `examples/diff.c` implementation of the `-B`
|
||||
(a.k.a. `--break-rewrites`) command line option to actually look for
|
||||
the optional `[<n>][/<m>]` configuration values. There is an
|
||||
existing comment that reads `/* TODO: parse thresholds */`. The
|
||||
trick to this one will be doing it in a manner that is clean and
|
||||
simple, but still handles the various cases correctly (e.g. `-B/70%`
|
||||
is apparently a legal setting).
|
||||
* Implement the `--log-size` option for `examples/log.c`. I think all
|
||||
the data is available, you would just need to add the code into the
|
||||
`print_commit()` routine (along with a way of passing the option
|
||||
into that function).
|
||||
* As an extension to the matching idea for `examples/log.c`, add the
|
||||
`-i` option to use `strcasestr()` for matches.
|
||||
* For `examples/log.c`, implement the `--first-parent` option now that
|
||||
libgit2 supports it in the revwalk API.
|
||||
* Pick a Git command that is not already emulated in `examples/` and write
|
||||
a new example that mirrors the behavior. Examples don't have to be
|
||||
perfect emulations, but should demonstrate how to use the libgit2 APIs
|
||||
to get results that are similar to Git commands. This lets you (and us)
|
||||
easily exercise a particular facet of the API and measure compatability
|
||||
and feature parity with core git.
|
||||
* Submit a PR to clarify documentation! While we do try to document all of
|
||||
the APIs, your fresh eyes on the documentation will find areas that are
|
||||
confusing much more easily.
|
||||
* Add support for the symref protocol extension, so we don't guess
|
||||
what the remote's default branch is
|
||||
[#2006](https://github.com/libgit2/libgit2/issues/2006)
|
||||
|
||||
If none of these appeal to you, take a look at our issues list to see if
|
||||
there are any unresolved issues you'd like to jump in on.
|
||||
|
||||
## Larger Projects
|
||||
|
||||
These are ideas for larger projects mostly taken from our backlog of
|
||||
[Issues](https://github.com/libgit2/libgit2/issues). Please don't dive
|
||||
into one of these as a first project for libgit2 - we'd rather get to
|
||||
know you first by successfully shipping your work on one of the smaller
|
||||
projects above.
|
||||
|
||||
* Port part of the Git test suite to run against the command line emulation
|
||||
in examples/
|
||||
* Fix symlink support for files in the .git directory (i.e. don't overwrite
|
||||
the symlinks when writing the file contents back out)
|
||||
* Implement a 'git describe' like API
|
||||
* Add hooks API to enumerate and manage hooks (not run them at this point)
|
||||
* Isolate logic of ignore evaluation into a standalone API
|
||||
* Upgrade internal libxdiff code to latest from core Git
|
||||
* Add a hashtable lookup for files in the index instead of binary search
|
||||
every time
|
||||
* Make the index write the cache out to disk (with tests to gain
|
||||
confidence that the caching invalidation works correctly)
|
||||
* Have the tree builder use a hash table when building instead of a
|
||||
list.
|
||||
* Move the tagopt mechanism to the newer git 1.9 interpretation of
|
||||
--tags [#2120](https://github.com/libgit2/libgit2/issues/2120)
|
41
README.md
41
README.md
@ -2,10 +2,11 @@ libgit2 - the Git linkable library
|
||||
==================================
|
||||
|
||||
[](http://travis-ci.org/libgit2/libgit2)
|
||||
[](https://scan.coverity.com/projects/639)
|
||||
|
||||
`libgit2` is a portable, pure C implementation of the Git core methods provided as a
|
||||
re-entrant linkable library with a solid API, allowing you to write native
|
||||
speed custom Git applications in any language with bindings.
|
||||
`libgit2` is a portable, pure C implementation of the Git core methods
|
||||
provided as a re-entrant linkable library with a solid API, allowing you to
|
||||
write native speed custom Git applications in any language with bindings.
|
||||
|
||||
`libgit2` is licensed under a **very permissive license** (GPLv2 with a special
|
||||
Linking Exception). This basically means that you can link it (unmodified)
|
||||
@ -19,18 +20,19 @@ Additionally, the example code has been released to the public domain (see the
|
||||
* API documentation: <http://libgit2.github.com/libgit2>
|
||||
* IRC: [#libgit2](irc://irc.freenode.net/libgit2) on irc.freenode.net.
|
||||
* Mailing list: The libgit2 mailing list was
|
||||
traditionally hosted in Librelist but has been deprecated. We encourage you to
|
||||
traditionally hosted in Librelist but has been deprecated. We encourage you to
|
||||
[use StackOverflow](http://stackoverflow.com/questions/tagged/libgit2) instead for any questions regarding
|
||||
the library, or [open an issue](https://github.com/libgit2/libgit2/issues)
|
||||
on GitHub for bug reports. The mailing list archives are still available at
|
||||
the library, or [open an issue](https://github.com/libgit2/libgit2/issues)
|
||||
on GitHub for bug reports. The mailing list archives are still available at
|
||||
<http://librelist.com/browser/libgit2/>.
|
||||
|
||||
|
||||
What It Can Do
|
||||
==============
|
||||
|
||||
`libgit2` is already very usable and is being used in production for many applications including the GitHub.com site, in Plastic SCM
|
||||
and also powering Microsoft's Visual Studio tools for Git. The library provides:
|
||||
`libgit2` is already very usable and is being used in production for many
|
||||
applications including the GitHub.com site, in Plastic SCM and also powering
|
||||
Microsoft's Visual Studio tools for Git. The library provides:
|
||||
|
||||
* SHA conversions, formatting and shortening
|
||||
* abstracted ODB backend system
|
||||
@ -64,7 +66,7 @@ Under Unix-like systems, like Linux, \*BSD and Mac OS X, libgit2 expects `pthrea
|
||||
they should be installed by default on all systems. Under Windows, libgit2 uses the native Windows API
|
||||
for threading.
|
||||
|
||||
The `libgit2` library is built using `CMake 2.6+` (<http://www.cmake.org>) on all platforms.
|
||||
The `libgit2` library is built using [CMake](<http://www.cmake.org>) (version 2.6 or newer) on all platforms.
|
||||
|
||||
On most systems you can build the library using the following commands
|
||||
|
||||
@ -164,11 +166,12 @@ Here are the bindings to libgit2 that are currently available:
|
||||
* libgit2-glib <https://live.gnome.org/Libgit2-glib>
|
||||
* Haskell
|
||||
* hgit2 <https://github.com/fpco/gitlib>
|
||||
* Java
|
||||
* Jagged <https://github.com/ethomson/jagged>
|
||||
* Lua
|
||||
* luagit2 <https://github.com/libgit2/luagit2>
|
||||
* .NET
|
||||
* libgit2sharp <https://github.com/libgit2/libgit2sharp>
|
||||
* libgit2net, low level bindings superseded by libgit2sharp <https://github.com/txdv/libgit2net>
|
||||
* Node.js
|
||||
* node-gitteh <https://github.com/libgit2/node-gitteh>
|
||||
* nodegit <https://github.com/tbranyen/nodegit>
|
||||
@ -182,8 +185,12 @@ Here are the bindings to libgit2 that are currently available:
|
||||
* Git-Raw <https://github.com/ghedo/p5-Git-Raw>
|
||||
* PHP
|
||||
* php-git <https://github.com/libgit2/php-git>
|
||||
* PowerShell
|
||||
* GitPowerShell <https://github.com/ethomson/gitpowershell>
|
||||
* Python
|
||||
* pygit2 <https://github.com/libgit2/pygit2>
|
||||
* R
|
||||
* git2r <https://github.com/ropensci/git2r>
|
||||
* Ruby
|
||||
* Rugged <https://github.com/libgit2/rugged>
|
||||
* Vala
|
||||
@ -195,14 +202,16 @@ we can add it to the list.
|
||||
How Can I Contribute?
|
||||
==================================
|
||||
|
||||
Check the [contribution guidelines](CONTRIBUTING.md).
|
||||
|
||||
Check the [contribution guidelines](CONTRIBUTING.md) to understand our
|
||||
workflow, the libgit2 [coding conventions](CONVENTIONS.md), and out list of
|
||||
[good starting projects](PROJECTS.md).
|
||||
|
||||
License
|
||||
==================================
|
||||
`libgit2` is under GPL2 **with linking exemption**. This means you
|
||||
can link to and use the library from any program, proprietary or open source; paid
|
||||
or gratis. However, you cannot modify libgit2 and distribute it without
|
||||
|
||||
`libgit2` is under GPL2 **with linking exemption**. This means you can link to
|
||||
and use the library from any program, proprietary or open source; paid or
|
||||
gratis. However, you cannot modify libgit2 and distribute it without
|
||||
supplying the source.
|
||||
|
||||
See the COPYING file for the full license text.
|
||||
See the [COPYING file](COPYING) for the full license text.
|
||||
|
16
cmake/Modules/AddCFlagIfSupported.cmake
Normal file
16
cmake/Modules/AddCFlagIfSupported.cmake
Normal file
@ -0,0 +1,16 @@
|
||||
# - Append compiler flag to CMAKE_C_FLAGS if compiler supports it
|
||||
# ADD_C_FLAG_IF_SUPPORTED(<flag>)
|
||||
# <flag> - the compiler flag to test
|
||||
# This internally calls the CHECK_C_COMPILER_FLAG macro.
|
||||
|
||||
INCLUDE(CheckCCompilerFlag)
|
||||
|
||||
MACRO(ADD_C_FLAG_IF_SUPPORTED _FLAG)
|
||||
STRING(TOUPPER ${_FLAG} UPCASE)
|
||||
STRING(REGEX REPLACE "^-" "" UPCASE_PRETTY ${UPCASE})
|
||||
CHECK_C_COMPILER_FLAG(${_FLAG} IS_${UPCASE_PRETTY}_SUPPORTED)
|
||||
|
||||
IF(IS_${UPCASE_PRETTY}_SUPPORTED)
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_FLAG}")
|
||||
ENDIF()
|
||||
ENDMACRO()
|
43
cmake/Modules/FindIconv.cmake
Normal file
43
cmake/Modules/FindIconv.cmake
Normal file
@ -0,0 +1,43 @@
|
||||
# - Try to find Iconv
|
||||
# Once done this will define
|
||||
#
|
||||
# ICONV_FOUND - system has Iconv
|
||||
# ICONV_INCLUDE_DIR - the Iconv include directory
|
||||
# ICONV_LIBRARIES - Link these to use Iconv
|
||||
#
|
||||
|
||||
IF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
|
||||
# Already in cache, be silent
|
||||
SET(ICONV_FIND_QUIETLY TRUE)
|
||||
ENDIF()
|
||||
|
||||
FIND_PATH(ICONV_INCLUDE_DIR iconv.h PATHS /opt/local/include NO_DEFAULT_PATH)
|
||||
FIND_PATH(ICONV_INCLUDE_DIR iconv.h)
|
||||
|
||||
FIND_LIBRARY(iconv_lib NAMES iconv libiconv libiconv-2 c NO_DEFAULT_PATH PATHS /opt/local/lib)
|
||||
FIND_LIBRARY(iconv_lib NAMES iconv libiconv libiconv-2 c)
|
||||
|
||||
IF(ICONV_INCLUDE_DIR AND iconv_lib)
|
||||
SET(ICONV_FOUND TRUE)
|
||||
ENDIF()
|
||||
|
||||
IF(ICONV_FOUND)
|
||||
# split iconv into -L and -l linker options, so we can set them for pkg-config
|
||||
GET_FILENAME_COMPONENT(iconv_path ${iconv_lib} PATH)
|
||||
GET_FILENAME_COMPONENT(iconv_name ${iconv_lib} NAME_WE)
|
||||
STRING(REGEX REPLACE "^lib" "" iconv_name ${iconv_name})
|
||||
SET(ICONV_LIBRARIES "-L${iconv_path} -l${iconv_name}")
|
||||
|
||||
IF(NOT ICONV_FIND_QUIETLY)
|
||||
MESSAGE(STATUS "Found Iconv: ${ICONV_LIBRARIES}")
|
||||
ENDIF(NOT ICONV_FIND_QUIETLY)
|
||||
ELSE()
|
||||
IF(Iconv_FIND_REQUIRED)
|
||||
MESSAGE(FATAL_ERROR "Could not find Iconv")
|
||||
ENDIF(Iconv_FIND_REQUIRED)
|
||||
ENDIF()
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
ICONV_INCLUDE_DIR
|
||||
ICONV_LIBRARIES
|
||||
)
|
13
deps/regex/regex.c
vendored
13
deps/regex/regex.c
vendored
@ -67,10 +67,17 @@
|
||||
#include "regex_internal.h"
|
||||
|
||||
#include "regex_internal.c"
|
||||
|
||||
#ifdef GAWK
|
||||
#define bool int
|
||||
#define true (1)
|
||||
#define false (0)
|
||||
# define bool int
|
||||
|
||||
# ifndef true
|
||||
# define true (1)
|
||||
# endif
|
||||
|
||||
# ifndef false
|
||||
# define false (0)
|
||||
# endif
|
||||
#endif
|
||||
#include "regcomp.c"
|
||||
#include "regexec.c"
|
||||
|
@ -21,7 +21,7 @@ content, everything goes through diff drivers that are implemented in
|
||||
External Objects
|
||||
----------------
|
||||
|
||||
* `git_diff_options` repesents user choices about how a diff should be
|
||||
* `git_diff_options` represents user choices about how a diff should be
|
||||
performed and is passed to most diff generating functions.
|
||||
* `git_diff_file` represents an item on one side of a possible delta
|
||||
* `git_diff_delta` represents a pair of items that have changed in some
|
||||
@ -37,7 +37,7 @@ External Objects
|
||||
header that compactly represents that information, and it will have a
|
||||
number of lines of context surrounding added and deleted lines.
|
||||
* A `line` is simple a line of data along with a `git_diff_line_t` value
|
||||
that tells how the data should be interpretted (e.g. context or added).
|
||||
that tells how the data should be interpreted (e.g. context or added).
|
||||
|
||||
Internal Objects
|
||||
----------------
|
||||
|
2
examples/.gitignore
vendored
2
examples/.gitignore
vendored
@ -8,4 +8,6 @@ init
|
||||
log
|
||||
rev-parse
|
||||
status
|
||||
tag
|
||||
for-each-ref
|
||||
*.dSYM
|
||||
|
@ -3,7 +3,8 @@
|
||||
CC = gcc
|
||||
CFLAGS = -g -I../include -I../src -Wall -Wextra -Wmissing-prototypes -Wno-missing-field-initializers
|
||||
LFLAGS = -L../build -lgit2 -lz
|
||||
APPS = general showindex diff rev-list cat-file status log rev-parse init blame
|
||||
APPS = general showindex diff rev-list cat-file status log rev-parse init blame tag
|
||||
APPS += for-each-ref
|
||||
|
||||
all: $(APPS)
|
||||
|
||||
|
@ -78,7 +78,7 @@ int print_matched_cb(const char *path, const char *matched_pathspec, void *paylo
|
||||
git_status_t status;
|
||||
(void)matched_pathspec;
|
||||
|
||||
if (git_status_file(&status, p.repo, path)) {
|
||||
if (git_status_file((unsigned int*)(&status), p.repo, path)) {
|
||||
return -1; //abort
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,11 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf sprintf_s
|
||||
#define strcasecmp strcmpi
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This example demonstrates how to invoke the libgit2 blame API to roughly
|
||||
* simulate the output of `git blame` and a few of its command line arguments.
|
||||
@ -26,6 +31,7 @@ struct opts {
|
||||
int M;
|
||||
int start_line;
|
||||
int end_line;
|
||||
int F;
|
||||
};
|
||||
static void parse_opts(struct opts *o, int argc, char *argv[]);
|
||||
|
||||
@ -47,6 +53,7 @@ int main(int argc, char *argv[])
|
||||
parse_opts(&o, argc, argv);
|
||||
if (o.M) blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES;
|
||||
if (o.C) blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES;
|
||||
if (o.F) blameopts.flags |= GIT_BLAME_FIRST_PARENT;
|
||||
|
||||
/** Open the repository. */
|
||||
check_lg2(git_repository_open_ext(&repo, ".", 0, NULL), "Couldn't open repository", NULL);
|
||||
@ -100,8 +107,9 @@ int main(int argc, char *argv[])
|
||||
if (break_on_null_hunk && !hunk) break;
|
||||
|
||||
if (hunk) {
|
||||
break_on_null_hunk = 1;
|
||||
char sig[128] = {0};
|
||||
break_on_null_hunk = 1;
|
||||
|
||||
|
||||
git_oid_tostr(oid, 10, &hunk->final_commit_id);
|
||||
snprintf(sig, 30, "%s <%s>", hunk->final_signature->name, hunk->final_signature->email);
|
||||
@ -141,6 +149,7 @@ static void usage(const char *msg, const char *arg)
|
||||
fprintf(stderr, " -L <n,m> process only line range n-m, counting from 1\n");
|
||||
fprintf(stderr, " -M find line moves within and across files\n");
|
||||
fprintf(stderr, " -C find line copies within and across files\n");
|
||||
fprintf(stderr, " -F follow only the first parent commits\n");
|
||||
fprintf(stderr, "\n");
|
||||
exit(1);
|
||||
}
|
||||
@ -169,6 +178,8 @@ static void parse_opts(struct opts *o, int argc, char *argv[])
|
||||
o->M = 1;
|
||||
else if (!strcasecmp(a, "-C"))
|
||||
o->C = 1;
|
||||
else if (!strcasecmp(a, "-F"))
|
||||
o->F = 1;
|
||||
else if (!strcasecmp(a, "-L")) {
|
||||
i++; a = argv[i];
|
||||
if (i >= argc) fatal("Not enough arguments to -L", NULL);
|
||||
|
@ -42,7 +42,7 @@ static void print_signature(const char *header, const git_signature *sig)
|
||||
static void show_blob(const git_blob *blob)
|
||||
{
|
||||
/* ? Does this need crlf filtering? */
|
||||
fwrite(git_blob_rawcontent(blob), git_blob_rawsize(blob), 1, stdout);
|
||||
fwrite(git_blob_rawcontent(blob), (size_t)git_blob_rawsize(blob), 1, stdout);
|
||||
}
|
||||
|
||||
/** Show each entry with its type, id and attributes */
|
||||
|
@ -156,7 +156,7 @@ int diff_output(
|
||||
const git_diff_line *l,
|
||||
void *p)
|
||||
{
|
||||
FILE *fp = p;
|
||||
FILE *fp = (FILE*)p;
|
||||
|
||||
(void)d; (void)h;
|
||||
|
||||
|
128
examples/diff.c
128
examples/diff.c
@ -33,12 +33,27 @@ static const char *colors[] = {
|
||||
"\033[36m" /* cyan */
|
||||
};
|
||||
|
||||
enum {
|
||||
OUTPUT_DIFF = (1 << 0),
|
||||
OUTPUT_STAT = (1 << 1),
|
||||
OUTPUT_SHORTSTAT = (1 << 2),
|
||||
OUTPUT_NUMSTAT = (1 << 3),
|
||||
OUTPUT_SUMMARY = (1 << 4)
|
||||
};
|
||||
|
||||
enum {
|
||||
CACHE_NORMAL = 0,
|
||||
CACHE_ONLY = 1,
|
||||
CACHE_NONE = 2
|
||||
};
|
||||
|
||||
/** The 'opts' struct captures all the various parsed command line options. */
|
||||
struct opts {
|
||||
git_diff_options diffopts;
|
||||
git_diff_find_options findopts;
|
||||
int color;
|
||||
int cached;
|
||||
int cache;
|
||||
int output;
|
||||
git_diff_format_t format;
|
||||
const char *treeish1;
|
||||
const char *treeish2;
|
||||
@ -46,9 +61,11 @@ struct opts {
|
||||
};
|
||||
|
||||
/** These functions are implemented at the end */
|
||||
static void usage(const char *message, const char *arg);
|
||||
static void parse_opts(struct opts *o, int argc, char *argv[]);
|
||||
static int color_printer(
|
||||
const git_diff_delta*, const git_diff_hunk*, const git_diff_line*, void*);
|
||||
static void diff_print_stats(git_diff *diff, struct opts *o);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@ -57,7 +74,7 @@ int main(int argc, char *argv[])
|
||||
git_diff *diff;
|
||||
struct opts o = {
|
||||
GIT_DIFF_OPTIONS_INIT, GIT_DIFF_FIND_OPTIONS_INIT,
|
||||
-1, 0, GIT_DIFF_FORMAT_PATCH, NULL, NULL, "."
|
||||
-1, 0, 0, GIT_DIFF_FORMAT_PATCH, NULL, NULL, "."
|
||||
};
|
||||
|
||||
git_threads_init();
|
||||
@ -74,6 +91,7 @@ int main(int argc, char *argv[])
|
||||
* * <sha1> --cached
|
||||
* * <sha1>
|
||||
* * --cached
|
||||
* * --nocache (don't use index data in diff at all)
|
||||
* * nothing
|
||||
*
|
||||
* Currently ranged arguments like <sha1>..<sha2> and <sha1>...<sha2>
|
||||
@ -89,20 +107,23 @@ int main(int argc, char *argv[])
|
||||
check_lg2(
|
||||
git_diff_tree_to_tree(&diff, repo, t1, t2, &o.diffopts),
|
||||
"diff trees", NULL);
|
||||
else if (t1 && o.cached)
|
||||
check_lg2(
|
||||
git_diff_tree_to_index(&diff, repo, t1, NULL, &o.diffopts),
|
||||
"diff tree to index", NULL);
|
||||
else if (o.cache != CACHE_NORMAL) {
|
||||
if (!t1)
|
||||
treeish_to_tree(&t1, repo, "HEAD");
|
||||
|
||||
if (o.cache == CACHE_NONE)
|
||||
check_lg2(
|
||||
git_diff_tree_to_workdir(&diff, repo, t1, &o.diffopts),
|
||||
"diff tree to working directory", NULL);
|
||||
else
|
||||
check_lg2(
|
||||
git_diff_tree_to_index(&diff, repo, t1, NULL, &o.diffopts),
|
||||
"diff tree to index", NULL);
|
||||
}
|
||||
else if (t1)
|
||||
check_lg2(
|
||||
git_diff_tree_to_workdir_with_index(&diff, repo, t1, &o.diffopts),
|
||||
"diff tree to working directory", NULL);
|
||||
else if (o.cached) {
|
||||
treeish_to_tree(&t1, repo, "HEAD");
|
||||
check_lg2(
|
||||
git_diff_tree_to_index(&diff, repo, t1, NULL, &o.diffopts),
|
||||
"diff tree to index", NULL);
|
||||
}
|
||||
else
|
||||
check_lg2(
|
||||
git_diff_index_to_workdir(&diff, repo, NULL, &o.diffopts),
|
||||
@ -117,15 +138,23 @@ int main(int argc, char *argv[])
|
||||
|
||||
/** Generate simple output using libgit2 display helper. */
|
||||
|
||||
if (o.color >= 0)
|
||||
fputs(colors[0], stdout);
|
||||
if (!o.output)
|
||||
o.output = OUTPUT_DIFF;
|
||||
|
||||
check_lg2(
|
||||
git_diff_print(diff, o.format, color_printer, &o.color),
|
||||
"displaying diff", NULL);
|
||||
if (o.output != OUTPUT_DIFF)
|
||||
diff_print_stats(diff, &o);
|
||||
|
||||
if (o.color >= 0)
|
||||
fputs(colors[0], stdout);
|
||||
if ((o.output & OUTPUT_DIFF) != 0) {
|
||||
if (o.color >= 0)
|
||||
fputs(colors[0], stdout);
|
||||
|
||||
check_lg2(
|
||||
git_diff_print(diff, o.format, color_printer, &o.color),
|
||||
"displaying diff", NULL);
|
||||
|
||||
if (o.color >= 0)
|
||||
fputs(colors[0], stdout);
|
||||
}
|
||||
|
||||
/** Cleanup before exiting. */
|
||||
|
||||
@ -200,16 +229,25 @@ static void parse_opts(struct opts *o, int argc, char *argv[])
|
||||
usage("Only one or two tree identifiers can be provided", NULL);
|
||||
}
|
||||
else if (!strcmp(a, "-p") || !strcmp(a, "-u") ||
|
||||
!strcmp(a, "--patch"))
|
||||
!strcmp(a, "--patch")) {
|
||||
o->output |= OUTPUT_DIFF;
|
||||
o->format = GIT_DIFF_FORMAT_PATCH;
|
||||
}
|
||||
else if (!strcmp(a, "--cached"))
|
||||
o->cached = 1;
|
||||
else if (!strcmp(a, "--name-only"))
|
||||
o->cache = CACHE_ONLY;
|
||||
else if (!strcmp(a, "--nocache"))
|
||||
o->cache = CACHE_NONE;
|
||||
else if (!strcmp(a, "--name-only") || !strcmp(a, "--format=name"))
|
||||
o->format = GIT_DIFF_FORMAT_NAME_ONLY;
|
||||
else if (!strcmp(a, "--name-status"))
|
||||
else if (!strcmp(a, "--name-status") ||
|
||||
!strcmp(a, "--format=name-status"))
|
||||
o->format = GIT_DIFF_FORMAT_NAME_STATUS;
|
||||
else if (!strcmp(a, "--raw"))
|
||||
else if (!strcmp(a, "--raw") || !strcmp(a, "--format=raw"))
|
||||
o->format = GIT_DIFF_FORMAT_RAW;
|
||||
else if (!strcmp(a, "--format=diff-index")) {
|
||||
o->format = GIT_DIFF_FORMAT_RAW;
|
||||
o->diffopts.id_abbrev = 40;
|
||||
}
|
||||
else if (!strcmp(a, "--color"))
|
||||
o->color = 0;
|
||||
else if (!strcmp(a, "--no-color"))
|
||||
@ -228,6 +266,18 @@ static void parse_opts(struct opts *o, int argc, char *argv[])
|
||||
o->diffopts.flags |= GIT_DIFF_INCLUDE_IGNORED;
|
||||
else if (!strcmp(a, "--untracked"))
|
||||
o->diffopts.flags |= GIT_DIFF_INCLUDE_UNTRACKED;
|
||||
else if (!strcmp(a, "--patience"))
|
||||
o->diffopts.flags |= GIT_DIFF_PATIENCE;
|
||||
else if (!strcmp(a, "--minimal"))
|
||||
o->diffopts.flags |= GIT_DIFF_MINIMAL;
|
||||
else if (!strcmp(a, "--stat"))
|
||||
o->output |= OUTPUT_STAT;
|
||||
else if (!strcmp(a, "--numstat"))
|
||||
o->output |= OUTPUT_NUMSTAT;
|
||||
else if (!strcmp(a, "--shortstat"))
|
||||
o->output |= OUTPUT_SHORTSTAT;
|
||||
else if (!strcmp(a, "--summary"))
|
||||
o->output |= OUTPUT_SUMMARY;
|
||||
else if (match_uint16_arg(
|
||||
&o->findopts.rename_threshold, &args, "-M") ||
|
||||
match_uint16_arg(
|
||||
@ -249,9 +299,39 @@ static void parse_opts(struct opts *o, int argc, char *argv[])
|
||||
&o->diffopts.context_lines, &args, "--unified") &&
|
||||
!match_uint16_arg(
|
||||
&o->diffopts.interhunk_lines, &args, "--inter-hunk-context") &&
|
||||
!match_uint16_arg(
|
||||
&o->diffopts.id_abbrev, &args, "--abbrev") &&
|
||||
!match_str_arg(&o->diffopts.old_prefix, &args, "--src-prefix") &&
|
||||
!match_str_arg(&o->diffopts.new_prefix, &args, "--dst-prefix") &&
|
||||
!match_str_arg(&o->dir, &args, "--git-dir"))
|
||||
usage("Unknown command line argument", a);
|
||||
}
|
||||
}
|
||||
|
||||
/** Display diff output with "--stat", "--numstat", or "--shortstat" */
|
||||
static void diff_print_stats(git_diff *diff, struct opts *o)
|
||||
{
|
||||
git_diff_stats *stats;
|
||||
git_buf b = GIT_BUF_INIT_CONST(NULL, 0);
|
||||
git_diff_stats_format_t format = 0;
|
||||
|
||||
check_lg2(
|
||||
git_diff_get_stats(&stats, diff), "generating stats for diff", NULL);
|
||||
|
||||
if (o->output & OUTPUT_STAT)
|
||||
format |= GIT_DIFF_STATS_FULL;
|
||||
if (o->output & OUTPUT_SHORTSTAT)
|
||||
format |= GIT_DIFF_STATS_SHORT;
|
||||
if (o->output & OUTPUT_NUMSTAT)
|
||||
format |= GIT_DIFF_STATS_NUMBER;
|
||||
if (o->output & OUTPUT_SUMMARY)
|
||||
format |= GIT_DIFF_STATS_INCLUDE_SUMMARY;
|
||||
|
||||
check_lg2(
|
||||
git_diff_stats_to_buf(&b, stats, format, 80), "formatting stats", NULL);
|
||||
|
||||
fputs(b.ptr, stdout);
|
||||
|
||||
git_buf_free(&b);
|
||||
git_diff_stats_free(stats);
|
||||
}
|
||||
|
46
examples/for-each-ref.c
Normal file
46
examples/for-each-ref.c
Normal file
@ -0,0 +1,46 @@
|
||||
#include <git2.h>
|
||||
#include <stdio.h>
|
||||
#include "common.h"
|
||||
|
||||
static int show_ref(git_reference *ref, void *data)
|
||||
{
|
||||
git_repository *repo = data;
|
||||
git_reference *resolved = NULL;
|
||||
char hex[GIT_OID_HEXSZ+1];
|
||||
const git_oid *oid;
|
||||
git_object *obj;
|
||||
|
||||
if (git_reference_type(ref) == GIT_REF_SYMBOLIC)
|
||||
check_lg2(git_reference_resolve(&resolved, ref),
|
||||
"Unable to resolve symbolic reference",
|
||||
git_reference_name(ref));
|
||||
|
||||
oid = git_reference_target(resolved ? resolved : ref);
|
||||
git_oid_fmt(hex, oid);
|
||||
hex[GIT_OID_HEXSZ] = 0;
|
||||
check_lg2(git_object_lookup(&obj, repo, oid, GIT_OBJ_ANY),
|
||||
"Unable to lookup object", hex);
|
||||
|
||||
printf("%s %-6s\t%s\n",
|
||||
hex,
|
||||
git_object_type2string(git_object_type(obj)),
|
||||
git_reference_name(ref));
|
||||
|
||||
if (resolved)
|
||||
git_reference_free(resolved);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
git_repository *repo;
|
||||
|
||||
if (argc != 1 || argv[1] /* silence -Wunused-parameter */)
|
||||
fatal("Sorry, no for-each-ref options supported yet", NULL);
|
||||
|
||||
check_lg2(git_repository_open(&repo, "."),
|
||||
"Could not open repository", NULL);
|
||||
check_lg2(git_reference_foreach(repo, show_ref, repo),
|
||||
"Could not iterate over references", NULL);
|
||||
return 0;
|
||||
}
|
@ -47,11 +47,10 @@
|
||||
// as an example.
|
||||
static void check_error(int error_code, const char *action)
|
||||
{
|
||||
const git_error *error = giterr_last();
|
||||
if (!error_code)
|
||||
return;
|
||||
|
||||
const git_error *error = giterr_last();
|
||||
|
||||
printf("Error %d %s - %s\n", error_code, action,
|
||||
(error && error->message) ? error->message : "???");
|
||||
|
||||
|
@ -54,8 +54,9 @@ struct log_options {
|
||||
int min_parents, max_parents;
|
||||
git_time_t before;
|
||||
git_time_t after;
|
||||
char *author;
|
||||
char *committer;
|
||||
const char *author;
|
||||
const char *committer;
|
||||
const char *grep;
|
||||
};
|
||||
|
||||
/** utility functions that parse options and help with log output */
|
||||
@ -65,6 +66,9 @@ static void print_time(const git_time *intime, const char *prefix);
|
||||
static void print_commit(git_commit *commit);
|
||||
static int match_with_parent(git_commit *commit, int i, git_diff_options *);
|
||||
|
||||
/** utility functions for filtering */
|
||||
static int signature_matches(const git_signature *sig, const char *filter);
|
||||
static int log_message_matches(const git_commit *commit, const char *filter);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@ -128,6 +132,15 @@ int main(int argc, char *argv[])
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!signature_matches(git_commit_author(commit), opt.author))
|
||||
continue;
|
||||
|
||||
if (!signature_matches(git_commit_committer(commit), opt.committer))
|
||||
continue;
|
||||
|
||||
if (!log_message_matches(commit, opt.grep))
|
||||
continue;
|
||||
|
||||
if (count++ < opt.skip)
|
||||
continue;
|
||||
if (opt.limit != -1 && printed++ >= opt.limit) {
|
||||
@ -172,6 +185,32 @@ int main(int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Determine if the given git_signature does not contain the filter text. */
|
||||
static int signature_matches(const git_signature *sig, const char *filter) {
|
||||
if (filter == NULL)
|
||||
return 1;
|
||||
|
||||
if (sig != NULL &&
|
||||
(strstr(sig->name, filter) != NULL ||
|
||||
strstr(sig->email, filter) != NULL))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int log_message_matches(const git_commit *commit, const char *filter) {
|
||||
const char *message = NULL;
|
||||
|
||||
if (filter == NULL)
|
||||
return 1;
|
||||
|
||||
if ((message = git_commit_message(commit)) != NULL &&
|
||||
strstr(message, filter) != NULL)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Push object (for hide or show) onto revwalker. */
|
||||
static void push_rev(struct log_state *s, git_object *obj, int hide)
|
||||
{
|
||||
@ -401,6 +440,12 @@ static int parse_options(
|
||||
set_sorting(s, GIT_SORT_TOPOLOGICAL);
|
||||
else if (!strcmp(a, "--reverse"))
|
||||
set_sorting(s, GIT_SORT_REVERSE);
|
||||
else if (match_str_arg(&opt->author, &args, "--author"))
|
||||
/** Found valid --author */;
|
||||
else if (match_str_arg(&opt->committer, &args, "--committer"))
|
||||
/** Found valid --committer */;
|
||||
else if (match_str_arg(&opt->grep, &args, "--grep"))
|
||||
/** Found valid --grep */;
|
||||
else if (match_str_arg(&s->repodir, &args, "--git-dir"))
|
||||
/** Found git-dir. */;
|
||||
else if (match_int_arg(&opt->skip, &args, "--skip", 0))
|
||||
|
@ -22,7 +22,7 @@ static void print_progress(const progress_data *pd)
|
||||
int index_percent = (100*pd->fetch_progress.indexed_objects) / pd->fetch_progress.total_objects;
|
||||
int checkout_percent = pd->total_steps > 0
|
||||
? (100 * pd->completed_steps) / pd->total_steps
|
||||
: 0.f;
|
||||
: 0;
|
||||
int kbytes = pd->fetch_progress.received_bytes / 1024;
|
||||
|
||||
if (pd->fetch_progress.received_objects == pd->fetch_progress.total_objects) {
|
||||
@ -62,7 +62,7 @@ int do_clone(git_repository *repo, int argc, char **argv)
|
||||
progress_data pd = {{0}};
|
||||
git_repository *cloned_repo = NULL;
|
||||
git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT;
|
||||
git_checkout_opts checkout_opts = GIT_CHECKOUT_OPTS_INIT;
|
||||
git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
|
||||
const char *url = argv[1];
|
||||
const char *path = argv[2];
|
||||
int error;
|
||||
|
@ -91,13 +91,13 @@ int fetch(git_repository *repo, int argc, char **argv)
|
||||
// Figure out whether it's a named remote or a URL
|
||||
printf("Fetching %s for repo %p\n", argv[1], repo);
|
||||
if (git_remote_load(&remote, repo, argv[1]) < 0) {
|
||||
if (git_remote_create_inmemory(&remote, repo, NULL, argv[1]) < 0)
|
||||
if (git_remote_create_anonymous(&remote, repo, argv[1], NULL) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set up the callbacks (only update_tips for now)
|
||||
callbacks.update_tips = &update_cb;
|
||||
callbacks.progress = &progress_cb;
|
||||
callbacks.sideband_progress = &progress_cb;
|
||||
callbacks.credentials = cred_acquire_cb;
|
||||
git_remote_set_callbacks(remote, &callbacks);
|
||||
|
||||
@ -156,7 +156,7 @@ int fetch(git_repository *repo, int argc, char **argv)
|
||||
// right commits. This may be needed even if there was no packfile
|
||||
// to download, which can happen e.g. when the branches have been
|
||||
// changed but all the neede objects are available locally.
|
||||
if (git_remote_update_tips(remote) < 0)
|
||||
if (git_remote_update_tips(remote, NULL, NULL) < 0)
|
||||
return -1;
|
||||
|
||||
git_remote_free(remote);
|
||||
|
@ -15,7 +15,7 @@ static int use_remote(git_repository *repo, char *name)
|
||||
// Find the remote by name
|
||||
error = git_remote_load(&remote, repo, name);
|
||||
if (error < 0) {
|
||||
error = git_remote_create_inmemory(&remote, repo, NULL, name);
|
||||
error = git_remote_create_anonymous(&remote, repo, name, NULL);
|
||||
if (error < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ int main (int argc, char** argv)
|
||||
for (i = 0; i < ecount; ++i) {
|
||||
const git_index_entry *e = git_index_get_byindex(index, i);
|
||||
|
||||
git_oid_fmt(out, &e->oid);
|
||||
git_oid_fmt(out, &e->id);
|
||||
|
||||
printf("File Path: %s\n", e->path);
|
||||
printf(" Stage: %d\n", git_index_entry_stage(e));
|
||||
|
@ -13,6 +13,12 @@
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#ifdef _WIN32
|
||||
# include <Windows.h>
|
||||
# define sleep(a) Sleep(a * 1000)
|
||||
#else
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This example demonstrates the use of the libgit2 status APIs,
|
||||
@ -44,19 +50,22 @@ enum {
|
||||
#define MAX_PATHSPEC 8
|
||||
|
||||
struct opts {
|
||||
git_status_options statusopt;
|
||||
char *repodir;
|
||||
char *pathspec[MAX_PATHSPEC];
|
||||
int npaths;
|
||||
int format;
|
||||
int zterm;
|
||||
int showbranch;
|
||||
git_status_options statusopt;
|
||||
char *repodir;
|
||||
char *pathspec[MAX_PATHSPEC];
|
||||
int npaths;
|
||||
int format;
|
||||
int zterm;
|
||||
int showbranch;
|
||||
int showsubmod;
|
||||
int repeat;
|
||||
};
|
||||
|
||||
static void parse_opts(struct opts *o, int argc, char *argv[]);
|
||||
static void show_branch(git_repository *repo, int format);
|
||||
static void print_long(git_status_list *status);
|
||||
static void print_short(git_repository *repo, git_status_list *status);
|
||||
static int print_submod(git_submodule *sm, const char *name, void *payload);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@ -84,6 +93,10 @@ int main(int argc, char *argv[])
|
||||
fatal("Cannot report status on bare repository",
|
||||
git_repository_path(repo));
|
||||
|
||||
show_status:
|
||||
if (o.repeat)
|
||||
printf("\033[H\033[2J");
|
||||
|
||||
/**
|
||||
* Run status on the repository
|
||||
*
|
||||
@ -98,17 +111,29 @@ int main(int argc, char *argv[])
|
||||
* about what results are presented.
|
||||
*/
|
||||
check_lg2(git_status_list_new(&status, repo, &o.statusopt),
|
||||
"Could not get status", NULL);
|
||||
"Could not get status", NULL);
|
||||
|
||||
if (o.showbranch)
|
||||
show_branch(repo, o.format);
|
||||
|
||||
if (o.showsubmod) {
|
||||
int submod_count = 0;
|
||||
check_lg2(git_submodule_foreach(repo, print_submod, &submod_count),
|
||||
"Cannot iterate submodules", o.repodir);
|
||||
}
|
||||
|
||||
if (o.format == FORMAT_LONG)
|
||||
print_long(status);
|
||||
else
|
||||
print_short(repo, status);
|
||||
|
||||
git_status_list_free(status);
|
||||
|
||||
if (o.repeat) {
|
||||
sleep(o.repeat);
|
||||
goto show_status;
|
||||
}
|
||||
|
||||
git_repository_free(repo);
|
||||
git_threads_shutdown();
|
||||
|
||||
@ -363,22 +388,25 @@ static void print_short(git_repository *repo, git_status_list *status)
|
||||
unsigned int smstatus = 0;
|
||||
|
||||
if (!git_submodule_lookup(
|
||||
&sm, repo, s->index_to_workdir->new_file.path) &&
|
||||
!git_submodule_status(&smstatus, sm))
|
||||
{
|
||||
if (smstatus & GIT_SUBMODULE_STATUS_WD_MODIFIED)
|
||||
extra = " (new commits)";
|
||||
else if (smstatus & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED)
|
||||
extra = " (modified content)";
|
||||
else if (smstatus & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED)
|
||||
extra = " (modified content)";
|
||||
else if (smstatus & GIT_SUBMODULE_STATUS_WD_UNTRACKED)
|
||||
extra = " (untracked content)";
|
||||
&sm, repo, s->index_to_workdir->new_file.path)) {
|
||||
|
||||
if (!git_submodule_status(&smstatus, sm)) {
|
||||
if (smstatus & GIT_SUBMODULE_STATUS_WD_MODIFIED)
|
||||
extra = " (new commits)";
|
||||
else if (smstatus & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED)
|
||||
extra = " (modified content)";
|
||||
else if (smstatus & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED)
|
||||
extra = " (modified content)";
|
||||
else if (smstatus & GIT_SUBMODULE_STATUS_WD_UNTRACKED)
|
||||
extra = " (untracked content)";
|
||||
}
|
||||
}
|
||||
|
||||
git_submodule_free(sm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Now that we have all the information, it's time to format the output.
|
||||
* Now that we have all the information, format the output.
|
||||
*/
|
||||
|
||||
if (s->head_to_index) {
|
||||
@ -414,6 +442,21 @@ static void print_short(git_repository *repo, git_status_list *status)
|
||||
}
|
||||
}
|
||||
|
||||
static int print_submod(git_submodule *sm, const char *name, void *payload)
|
||||
{
|
||||
int *count = payload;
|
||||
(void)name;
|
||||
|
||||
if (*count == 0)
|
||||
printf("# Submodules\n");
|
||||
(*count)++;
|
||||
|
||||
printf("# - submodule '%s' at %s\n",
|
||||
git_submodule_name(sm), git_submodule_path(sm));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse options that git's status command supports.
|
||||
*/
|
||||
@ -459,6 +502,12 @@ static void parse_opts(struct opts *o, int argc, char *argv[])
|
||||
o->statusopt.flags |= GIT_STATUS_OPT_EXCLUDE_SUBMODULES;
|
||||
else if (!strncmp(a, "--git-dir=", strlen("--git-dir=")))
|
||||
o->repodir = a + strlen("--git-dir=");
|
||||
else if (!strcmp(a, "--repeat"))
|
||||
o->repeat = 10;
|
||||
else if (match_int_arg(&o->repeat, &args, "--repeat", 0))
|
||||
/* okay */;
|
||||
else if (!strcmp(a, "--list-submodules"))
|
||||
o->showsubmod = 1;
|
||||
else
|
||||
check_lg2(-1, "Unsupported option", a);
|
||||
}
|
||||
|
319
examples/tag.c
Normal file
319
examples/tag.c
Normal file
@ -0,0 +1,319 @@
|
||||
/*
|
||||
* libgit2 "tag" example - shows how to list, create and delete tags
|
||||
*
|
||||
* Written by the libgit2 contributors
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all copyright
|
||||
* and related and neighboring rights to this software to the public domain
|
||||
* worldwide. This software is distributed without any warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication along
|
||||
* with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/**
|
||||
* The following example partially reimplements the `git tag` command
|
||||
* and some of its options.
|
||||
*
|
||||
* These commands should work:
|
||||
|
||||
* - Tag name listing (`tag`)
|
||||
* - Filtered tag listing with messages (`tag -n3 -l "v0.1*"`)
|
||||
* - Lightweight tag creation (`tag test v0.18.0`)
|
||||
* - Tag creation (`tag -a -m "Test message" test v0.18.0`)
|
||||
* - Tag deletion (`tag -d test`)
|
||||
*
|
||||
* The command line parsing logic is simplified and doesn't handle
|
||||
* all of the use cases.
|
||||
*/
|
||||
|
||||
/** tag_options represents the parsed command line options */
|
||||
typedef struct {
|
||||
const char *message;
|
||||
const char *pattern;
|
||||
const char *tag_name;
|
||||
const char *target;
|
||||
int num_lines;
|
||||
int force;
|
||||
} tag_options;
|
||||
|
||||
/** tag_state represents the current program state for dragging around */
|
||||
typedef struct {
|
||||
git_repository *repo;
|
||||
tag_options *opts;
|
||||
} tag_state;
|
||||
|
||||
/** An action to execute based on the command line arguments */
|
||||
typedef void (*tag_action)(tag_state *state);
|
||||
typedef struct args_info args_info;
|
||||
|
||||
static void check(int result, const char *message)
|
||||
{
|
||||
if (result) fatal(message, NULL);
|
||||
}
|
||||
|
||||
/** Tag listing: Print individual message lines */
|
||||
static void print_list_lines(const char *message, const tag_state *state)
|
||||
{
|
||||
const char *msg = message;
|
||||
int num = state->opts->num_lines - 1;
|
||||
|
||||
if (!msg) return;
|
||||
|
||||
/** first line - headline */
|
||||
while(*msg && *msg != '\n') printf("%c", *msg++);
|
||||
|
||||
/** skip over new lines */
|
||||
while(*msg && *msg == '\n') msg++;
|
||||
|
||||
printf("\n");
|
||||
|
||||
/** print just headline? */
|
||||
if (num == 0) return;
|
||||
if (*msg && msg[1]) printf("\n");
|
||||
|
||||
/** print individual commit/tag lines */
|
||||
while (*msg && num-- >= 2) {
|
||||
printf(" ");
|
||||
|
||||
while (*msg && *msg != '\n') printf("%c", *msg++);
|
||||
|
||||
/** handle consecutive new lines */
|
||||
if (*msg && *msg == '\n' && msg[1] == '\n') {
|
||||
num--;
|
||||
printf("\n");
|
||||
}
|
||||
while(*msg && *msg == '\n') msg++;
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/** Tag listing: Print an actual tag object */
|
||||
static void print_tag(git_tag *tag, const tag_state *state)
|
||||
{
|
||||
printf("%-16s", git_tag_name(tag));
|
||||
|
||||
if (state->opts->num_lines) {
|
||||
const char *msg = git_tag_message(tag);
|
||||
print_list_lines(msg, state);
|
||||
} else {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/** Tag listing: Print a commit (target of a lightweight tag) */
|
||||
static void print_commit(git_commit *commit, const char *name,
|
||||
const tag_state *state)
|
||||
{
|
||||
printf("%-16s", name);
|
||||
|
||||
if (state->opts->num_lines) {
|
||||
const char *msg = git_commit_message(commit);
|
||||
print_list_lines(msg, state);
|
||||
} else {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/** Tag listing: Fallback, should not happen */
|
||||
static void print_name(const char *name)
|
||||
{
|
||||
printf("%s\n", name);
|
||||
}
|
||||
|
||||
/** Tag listing: Lookup tags based on ref name and dispatch to print */
|
||||
static int each_tag(const char *name, tag_state *state)
|
||||
{
|
||||
git_repository *repo = state->repo;
|
||||
git_object *obj;
|
||||
|
||||
check_lg2(git_revparse_single(&obj, repo, name),
|
||||
"Failed to lookup rev", name);
|
||||
|
||||
switch (git_object_type(obj)) {
|
||||
case GIT_OBJ_TAG:
|
||||
print_tag((git_tag *) obj, state);
|
||||
break;
|
||||
case GIT_OBJ_COMMIT:
|
||||
print_commit((git_commit *) obj, name, state);
|
||||
break;
|
||||
default:
|
||||
print_name(name);
|
||||
}
|
||||
|
||||
git_object_free(obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void action_list_tags(tag_state *state)
|
||||
{
|
||||
const char *pattern = state->opts->pattern;
|
||||
git_strarray tag_names = {0};
|
||||
size_t i;
|
||||
|
||||
check_lg2(git_tag_list_match(&tag_names, pattern ? pattern : "*", state->repo),
|
||||
"Unable to get list of tags", NULL);
|
||||
|
||||
for(i = 0; i < tag_names.count; i++) {
|
||||
each_tag(tag_names.strings[i], state);
|
||||
}
|
||||
|
||||
git_strarray_free(&tag_names);
|
||||
}
|
||||
|
||||
static void action_delete_tag(tag_state *state)
|
||||
{
|
||||
tag_options *opts = state->opts;
|
||||
git_object *obj;
|
||||
git_buf abbrev_oid = {0};
|
||||
|
||||
check(!opts->tag_name, "Name required");
|
||||
|
||||
check_lg2(git_revparse_single(&obj, state->repo, opts->tag_name),
|
||||
"Failed to lookup rev", opts->tag_name);
|
||||
|
||||
check_lg2(git_object_short_id(&abbrev_oid, obj),
|
||||
"Unable to get abbreviated OID", opts->tag_name);
|
||||
|
||||
check_lg2(git_tag_delete(state->repo, opts->tag_name),
|
||||
"Unable to delete tag", opts->tag_name);
|
||||
|
||||
printf("Deleted tag '%s' (was %s)\n", opts->tag_name, abbrev_oid.ptr);
|
||||
|
||||
git_buf_free(&abbrev_oid);
|
||||
git_object_free(obj);
|
||||
}
|
||||
|
||||
static void action_create_lighweight_tag(tag_state *state)
|
||||
{
|
||||
git_repository *repo = state->repo;
|
||||
tag_options *opts = state->opts;
|
||||
git_oid oid;
|
||||
git_object *target;
|
||||
|
||||
check(!opts->tag_name, "Name required");
|
||||
|
||||
if (!opts->target) opts->target = "HEAD";
|
||||
|
||||
check(!opts->target, "Target required");
|
||||
|
||||
check_lg2(git_revparse_single(&target, repo, opts->target),
|
||||
"Unable to resolve spec", opts->target);
|
||||
|
||||
check_lg2(git_tag_create_lightweight(&oid, repo, opts->tag_name,
|
||||
target, opts->force), "Unable to create tag", NULL);
|
||||
|
||||
git_object_free(target);
|
||||
}
|
||||
|
||||
static void action_create_tag(tag_state *state)
|
||||
{
|
||||
git_repository *repo = state->repo;
|
||||
tag_options *opts = state->opts;
|
||||
git_signature *tagger;
|
||||
git_oid oid;
|
||||
git_object *target;
|
||||
|
||||
check(!opts->tag_name, "Name required");
|
||||
check(!opts->message, "Message required");
|
||||
|
||||
if (!opts->target) opts->target = "HEAD";
|
||||
|
||||
check_lg2(git_revparse_single(&target, repo, opts->target),
|
||||
"Unable to resolve spec", opts->target);
|
||||
|
||||
check_lg2(git_signature_default(&tagger, repo),
|
||||
"Unable to create signature", NULL);
|
||||
|
||||
check_lg2(git_tag_create(&oid, repo, opts->tag_name,
|
||||
target, tagger, opts->message, opts->force), "Unable to create tag", NULL);
|
||||
|
||||
git_object_free(target);
|
||||
git_signature_free(tagger);
|
||||
}
|
||||
|
||||
static void print_usage()
|
||||
{
|
||||
fprintf(stderr, "usage: see `git help tag`\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/** Parse command line arguments and choose action to run when done */
|
||||
static void parse_options(tag_action *action, tag_options *opts, int argc, char **argv)
|
||||
{
|
||||
args_info args = ARGS_INFO_INIT;
|
||||
*action = &action_list_tags;
|
||||
|
||||
for (args.pos = 1; args.pos < argc; ++args.pos) {
|
||||
const char *curr = argv[args.pos];
|
||||
|
||||
if (curr[0] != '-') {
|
||||
if (!opts->tag_name)
|
||||
opts->tag_name = curr;
|
||||
else if (!opts->target)
|
||||
opts->target = curr;
|
||||
else
|
||||
print_usage();
|
||||
|
||||
if (*action != &action_create_tag)
|
||||
*action = &action_create_lighweight_tag;
|
||||
} else if (!strcmp(curr, "-n")) {
|
||||
opts->num_lines = 1;
|
||||
*action = &action_list_tags;
|
||||
} else if (!strcmp(curr, "-a")) {
|
||||
*action = &action_create_tag;
|
||||
} else if (!strcmp(curr, "-f")) {
|
||||
opts->force = 1;
|
||||
} else if (match_int_arg(&opts->num_lines, &args, "-n", 0)) {
|
||||
*action = &action_list_tags;
|
||||
} else if (match_str_arg(&opts->pattern, &args, "-l")) {
|
||||
*action = &action_list_tags;
|
||||
} else if (match_str_arg(&opts->tag_name, &args, "-d")) {
|
||||
*action = &action_delete_tag;
|
||||
} else if (match_str_arg(&opts->message, &args, "-m")) {
|
||||
*action = &action_create_tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialize tag_options struct */
|
||||
static void tag_options_init(tag_options *opts)
|
||||
{
|
||||
memset(opts, 0, sizeof(*opts));
|
||||
|
||||
opts->message = NULL;
|
||||
opts->pattern = NULL;
|
||||
opts->tag_name = NULL;
|
||||
opts->target = NULL;
|
||||
opts->num_lines = 0;
|
||||
opts->force = 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
git_repository *repo;
|
||||
tag_options opts;
|
||||
tag_action action;
|
||||
tag_state state;
|
||||
|
||||
git_threads_init();
|
||||
|
||||
check_lg2(git_repository_open_ext(&repo, ".", 0, NULL),
|
||||
"Could not open repository", NULL);
|
||||
|
||||
tag_options_init(&opts);
|
||||
parse_options(&action, &opts, argc, argv);
|
||||
|
||||
state.repo = repo;
|
||||
state.opts = &opts;
|
||||
action(&state);
|
||||
|
||||
git_repository_free(repo);
|
||||
git_threads_shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
@ -28,9 +28,6 @@
|
||||
# his/her consent on a patch-by-patch basis.
|
||||
# "???" means the person is a prominent contributor who has
|
||||
# not yet made his/her standpoint clear.
|
||||
# "ign" means the authors consent is ignored for the purpose
|
||||
# of libification. This is because the author has contributed
|
||||
# to areas that aren't interesting for the library.
|
||||
#
|
||||
# Please try to keep the list alphabetically ordered. It will
|
||||
# help in case we get all 600-ish git.git authors on it.
|
||||
@ -39,33 +36,39 @@
|
||||
# but has otherwise not contributed to git.)
|
||||
#
|
||||
ok Adam Simpkins <adam@adamsimpkins.net> (http transport)
|
||||
ok Adrian Johnson <ajohnson@redneon.com>
|
||||
ok Alexey Shumkin <alex.crezoff@gmail.com>
|
||||
ok Andreas Ericsson <ae@op5.se>
|
||||
ok Boyd Lynn Gerber <gerberb@zenez.com>
|
||||
ok Brandon Casey <drafnel@gmail.com>
|
||||
ok Brian Downing <bdowning@lavos.net>
|
||||
ok Brian Gernhardt <benji@silverinsanity.com>
|
||||
ok Christian Couder <chriscool@tuxfamily.org>
|
||||
ok Daniel Barkalow <barkalow@iabervon.org>
|
||||
ok Florian Forster <octo@verplant.org>
|
||||
ok Gustaf Hendeby <hendeby@isy.liu.se>
|
||||
ok Holger Weiss <holger@zedat.fu-berlin.de>
|
||||
ok Jeff King <peff@peff.net>
|
||||
ok Johannes Schindelin <Johannes.Schindelin@gmx.de>
|
||||
ok Johannes Sixt <j6t@kdbg.org>
|
||||
ask Jonathan Nieder <jrnieder@gmail.com>
|
||||
ok Junio C Hamano <gitster@pobox.com>
|
||||
ok Kristian Høgsberg <krh@redhat.com>
|
||||
ok Linus Torvalds <torvalds@linux-foundation.org>
|
||||
ok Lukas Sandström <lukass@etek.chalmers.se>
|
||||
ok Matthieu Moy <Matthieu.Moy@imag.fr>
|
||||
ign Mike McCormack <mike@codeweavers.com> (imap-send)
|
||||
ok Michael Haggerty <mhagger@alum.mit.edu>
|
||||
ok Nicolas Pitre <nico@fluxnic.net> <nico@cam.org>
|
||||
ok Paolo Bonzini <bonzini@gnu.org>
|
||||
ok Paul Kocher <paul@cryptography.com>
|
||||
ok Peter Hagervall <hager@cs.umu.se>
|
||||
ok Petr Onderka <gsvick@gmail.com>
|
||||
ok Pierre Habouzit <madcoder@debian.org>
|
||||
ok Pieter de Bie <pdebie@ai.rug.nl>
|
||||
ok René Scharfe <rene.scharfe@lsrfire.ath.cx>
|
||||
ign Robert Shearman <rob@codeweavers.com> (imap-send)
|
||||
ok Sebastian Schuberth <sschuberth@gmail.com>
|
||||
ok Shawn O. Pearce <spearce@spearce.org>
|
||||
ok Steffen Prohaska <prohaska@zib.de>
|
||||
ok Sven Verdoolaege <skimo@kotnet.org>
|
||||
ask Thomas Rast <tr@thomasrast.ch> (ok before 6-Oct-2013)
|
||||
ok Torsten Bögershausen <tboegi@web.de>
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "git2/branch.h"
|
||||
#include "git2/buffer.h"
|
||||
#include "git2/checkout.h"
|
||||
#include "git2/cherrypick.h"
|
||||
#include "git2/clone.h"
|
||||
#include "git2/commit.h"
|
||||
#include "git2/common.h"
|
||||
@ -43,6 +44,7 @@
|
||||
#include "git2/remote.h"
|
||||
#include "git2/repository.h"
|
||||
#include "git2/reset.h"
|
||||
#include "git2/revert.h"
|
||||
#include "git2/revparse.h"
|
||||
#include "git2/revwalk.h"
|
||||
#include "git2/signature.h"
|
||||
|
@ -199,8 +199,9 @@ typedef int (*git_attr_foreach_cb)(const char *name, const char *value, void *pa
|
||||
* only once per attribute name, even if there are multiple
|
||||
* rules for a given file. The highest priority rule will be
|
||||
* used. Return a non-zero value from this to stop looping.
|
||||
* The value will be returned from `git_attr_foreach`.
|
||||
* @param payload Passed on as extra parameter to callback function.
|
||||
* @return 0 on success, GIT_EUSER on non-zero callback, or error code
|
||||
* @return 0 on success, non-zero callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_attr_foreach(
|
||||
git_repository *repo,
|
||||
|
@ -40,6 +40,9 @@ typedef enum {
|
||||
* commit (like `git blame -CCC`). Implies SAME_COMMIT_COPIES.
|
||||
* NOT IMPLEMENTED. */
|
||||
GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES = (1<<3),
|
||||
/** Restrict the search of commits to those reachable following only the
|
||||
* first parents. */
|
||||
GIT_BLAME_FIRST_PARENT = (1<<4),
|
||||
} git_blame_flag_t;
|
||||
|
||||
/**
|
||||
@ -79,6 +82,18 @@ typedef struct git_blame_options {
|
||||
#define GIT_BLAME_OPTIONS_VERSION 1
|
||||
#define GIT_BLAME_OPTIONS_INIT {GIT_BLAME_OPTIONS_VERSION}
|
||||
|
||||
/**
|
||||
* Initializes a `git_blame_options` with default values. Equivalent to
|
||||
* creating an instance with GIT_BLAME_OPTIONS_INIT.
|
||||
*
|
||||
* @param opts The `git_blame_options` struct to initialize
|
||||
* @param version Version of struct; pass `GIT_BLAME_OPTIONS_VERSION`
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_blame_init_options(
|
||||
git_blame_options *opts,
|
||||
unsigned int version);
|
||||
|
||||
/**
|
||||
* Structure that represents a blame hunk.
|
||||
*
|
||||
@ -183,7 +198,7 @@ GIT_EXTERN(int) git_blame_buffer(
|
||||
git_blame **out,
|
||||
git_blame *reference,
|
||||
const char *buffer,
|
||||
uint32_t buffer_len);
|
||||
size_t buffer_len);
|
||||
|
||||
/**
|
||||
* Free memory allocated by git_blame_file or git_blame_buffer.
|
||||
|
@ -84,7 +84,7 @@ GIT_EXTERN(git_repository *) git_blob_owner(const git_blob *blob);
|
||||
* time.
|
||||
*
|
||||
* @param blob pointer to the blob
|
||||
* @return the pointer; NULL if the blob has no contents
|
||||
* @return the pointer
|
||||
*/
|
||||
GIT_EXTERN(const void *) git_blob_rawcontent(const git_blob *blob);
|
||||
|
||||
@ -159,37 +159,32 @@ typedef int (*git_blob_chunk_cb)(char *content, size_t max_length, void *payload
|
||||
* Write a loose blob to the Object Database from a
|
||||
* provider of chunks of data.
|
||||
*
|
||||
* Provided the `hintpath` parameter is filled, its value
|
||||
* will help to determine what git filters should be applied
|
||||
* to the object before it can be placed to the object database.
|
||||
* If the `hintpath` parameter is filled, it will be used to determine
|
||||
* what git filters should be applied to the object before it is written
|
||||
* to the object database.
|
||||
*
|
||||
* The implementation of the callback MUST respect the following rules:
|
||||
*
|
||||
* The implementation of the callback has to respect the
|
||||
* following rules:
|
||||
* - `content` must be filled by the callback. The maximum number of
|
||||
* bytes that the buffer can accept per call is defined by the
|
||||
* `max_length` parameter. Allocation and freeing of the buffer will
|
||||
* be taken care of by libgit2.
|
||||
*
|
||||
* - `content` will have to be filled by the consumer. The maximum number
|
||||
* of bytes that the buffer can accept per call is defined by the
|
||||
* `max_length` parameter. Allocation and freeing of the buffer will be taken
|
||||
* care of by the function.
|
||||
* - The `callback` must return the number of bytes that have been
|
||||
* written to the `content` buffer.
|
||||
*
|
||||
* - The callback is expected to return the number of bytes
|
||||
* that `content` have been filled with.
|
||||
*
|
||||
* - When there is no more data to stream, the callback should
|
||||
* return 0. This will prevent it from being invoked anymore.
|
||||
*
|
||||
* - When an error occurs, the callback should return -1.
|
||||
* - When there is no more data to stream, `callback` should return
|
||||
* 0. This will prevent it from being invoked anymore.
|
||||
*
|
||||
* - If an error occurs, the callback should return a negative value.
|
||||
* This value will be returned to the caller.
|
||||
*
|
||||
* @param id Return the id of the written blob
|
||||
*
|
||||
* @param repo repository where the blob will be written.
|
||||
* This repository can be bare or not.
|
||||
*
|
||||
* @param hintpath if not NULL, will help selecting the filters
|
||||
* to apply onto the content of the blob to be created.
|
||||
*
|
||||
* @return 0 or an error code
|
||||
* @param repo Repository where the blob will be written.
|
||||
* This repository can be bare or not.
|
||||
* @param hintpath If not NULL, will be used to select data filters
|
||||
* to apply onto the content of the blob to be created.
|
||||
* @return 0 or error code (from either libgit2 or callback function)
|
||||
*/
|
||||
GIT_EXTERN(int) git_blob_create_fromchunks(
|
||||
git_oid *id,
|
||||
@ -201,26 +196,27 @@ GIT_EXTERN(int) git_blob_create_fromchunks(
|
||||
/**
|
||||
* Write an in-memory buffer to the ODB as a blob
|
||||
*
|
||||
* @param oid return the oid of the written blob
|
||||
* @param id return the id of the written blob
|
||||
* @param repo repository where to blob will be written
|
||||
* @param buffer data to be written into the blob
|
||||
* @param len length of the data
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *buffer, size_t len);
|
||||
GIT_EXTERN(int) git_blob_create_frombuffer(
|
||||
git_oid *id, git_repository *repo, const void *buffer, size_t len);
|
||||
|
||||
/**
|
||||
* Determine if the blob content is most certainly binary or not.
|
||||
*
|
||||
* The heuristic used to guess if a file is binary is taken from core git:
|
||||
* Searching for NUL bytes and looking for a reasonable ratio of printable
|
||||
* to non-printable characters among the first 4000 bytes.
|
||||
* to non-printable characters among the first 8000 bytes.
|
||||
*
|
||||
* @param blob The blob which content should be analyzed
|
||||
* @return 1 if the content of the blob is detected
|
||||
* as binary; 0 otherwise.
|
||||
*/
|
||||
GIT_EXTERN(int) git_blob_is_binary(git_blob *blob);
|
||||
GIT_EXTERN(int) git_blob_is_binary(const git_blob *blob);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
|
@ -43,6 +43,12 @@ GIT_BEGIN_DECL
|
||||
*
|
||||
* @param force Overwrite existing branch.
|
||||
*
|
||||
* @param signature The identity that will used to populate the reflog entry
|
||||
*
|
||||
* @param log_message The one line long message to be appended to the reflog.
|
||||
* If NULL, the default is "Branch: created"; if you want something more
|
||||
* useful, provide a message.
|
||||
*
|
||||
* @return 0, GIT_EINVALIDSPEC or an error code.
|
||||
* A proper reference is written in the refs/heads namespace
|
||||
* pointing to the provided target commit.
|
||||
@ -52,7 +58,9 @@ GIT_EXTERN(int) git_branch_create(
|
||||
git_repository *repo,
|
||||
const char *branch_name,
|
||||
const git_commit *target,
|
||||
int force);
|
||||
int force,
|
||||
const git_signature *signature,
|
||||
const char *log_message);
|
||||
|
||||
/**
|
||||
* Delete an existing branch reference.
|
||||
@ -76,7 +84,7 @@ typedef struct git_branch_iterator git_branch_iterator;
|
||||
* @param repo Repository where to find the branches.
|
||||
* @param list_flags Filtering flags for the branch
|
||||
* listing. Valid values are GIT_BRANCH_LOCAL, GIT_BRANCH_REMOTE
|
||||
* or a combination of the two.
|
||||
* or GIT_BRANCH_ALL.
|
||||
*
|
||||
* @return 0 on success or an error code
|
||||
*/
|
||||
@ -115,13 +123,19 @@ GIT_EXTERN(void) git_branch_iterator_free(git_branch_iterator *iter);
|
||||
*
|
||||
* @param force Overwrite existing branch.
|
||||
*
|
||||
* @param signature The identity that will used to populate the reflog entry
|
||||
*
|
||||
* @param log_message The one line long message to be appended to the reflog
|
||||
*
|
||||
* @return 0 on success, GIT_EINVALIDSPEC or an error code.
|
||||
*/
|
||||
GIT_EXTERN(int) git_branch_move(
|
||||
git_reference **out,
|
||||
git_reference *branch,
|
||||
const char *new_branch_name,
|
||||
int force);
|
||||
int force,
|
||||
const git_signature *signature,
|
||||
const char *log_message);
|
||||
|
||||
/**
|
||||
* Lookup a branch by its name in a repository.
|
||||
@ -165,8 +179,9 @@ GIT_EXTERN(int) git_branch_lookup(
|
||||
* @return 0 on success; otherwise an error code (e.g., if the
|
||||
* ref is no local or remote branch).
|
||||
*/
|
||||
GIT_EXTERN(int) git_branch_name(const char **out,
|
||||
git_reference *ref);
|
||||
GIT_EXTERN(int) git_branch_name(
|
||||
const char **out,
|
||||
const git_reference *ref);
|
||||
|
||||
/**
|
||||
* Return the reference supporting the remote tracking branch,
|
||||
@ -182,7 +197,7 @@ GIT_EXTERN(int) git_branch_name(const char **out,
|
||||
*/
|
||||
GIT_EXTERN(int) git_branch_upstream(
|
||||
git_reference **out,
|
||||
git_reference *branch);
|
||||
const git_reference *branch);
|
||||
|
||||
/**
|
||||
* Set the upstream configuration for a given local branch
|
||||
@ -200,25 +215,20 @@ GIT_EXTERN(int) git_branch_set_upstream(git_reference *branch, const char *upstr
|
||||
* Return the name of the reference supporting the remote tracking branch,
|
||||
* given the name of a local branch reference.
|
||||
*
|
||||
* @param tracking_branch_name_out The user-allocated buffer which will be
|
||||
* filled with the name of the reference. Pass NULL if you just want to
|
||||
* get the needed size of the name of the reference as the output value.
|
||||
*
|
||||
* @param buffer_size Size of the `out` buffer in bytes.
|
||||
* @param out Pointer to the user-allocated git_buf which will be
|
||||
* filled with the name of the reference.
|
||||
*
|
||||
* @param repo the repository where the branches live
|
||||
*
|
||||
* @param canonical_branch_name name of the local branch.
|
||||
* @param refname reference name of the local branch.
|
||||
*
|
||||
* @return number of characters in the reference name
|
||||
* including the trailing NUL byte; GIT_ENOTFOUND when no remote tracking
|
||||
* reference exists, otherwise an error code.
|
||||
* @return 0, GIT_ENOTFOUND when no remote tracking reference exists,
|
||||
* otherwise an error code.
|
||||
*/
|
||||
GIT_EXTERN(int) git_branch_upstream_name(
|
||||
char *tracking_branch_name_out,
|
||||
size_t buffer_size,
|
||||
git_buf *out,
|
||||
git_repository *repo,
|
||||
const char *canonical_branch_name);
|
||||
const char *refname);
|
||||
|
||||
/**
|
||||
* Determine if the current local branch is pointed at by HEAD.
|
||||
@ -229,30 +239,24 @@ GIT_EXTERN(int) git_branch_upstream_name(
|
||||
* error code otherwise.
|
||||
*/
|
||||
GIT_EXTERN(int) git_branch_is_head(
|
||||
git_reference *branch);
|
||||
const git_reference *branch);
|
||||
|
||||
/**
|
||||
* Return the name of remote that the remote tracking branch belongs to.
|
||||
*
|
||||
* @param remote_name_out The user-allocated buffer which will be
|
||||
* filled with the name of the remote. Pass NULL if you just want to
|
||||
* get the needed size of the name of the remote as the output value.
|
||||
*
|
||||
* @param buffer_size Size of the `out` buffer in bytes.
|
||||
* @param out Pointer to the user-allocated git_buf which will be filled iwth the name of the remote.
|
||||
*
|
||||
* @param repo The repository where the branch lives.
|
||||
*
|
||||
* @param canonical_branch_name name of the remote tracking branch.
|
||||
*
|
||||
* @return Number of characters in the reference name
|
||||
* including the trailing NUL byte; GIT_ENOTFOUND
|
||||
* @return 0, GIT_ENOTFOUND
|
||||
* when no remote matching remote was found,
|
||||
* GIT_EAMBIGUOUS when the branch maps to several remotes,
|
||||
* otherwise an error code.
|
||||
*/
|
||||
GIT_EXTERN(int) git_branch_remote_name(
|
||||
char *remote_name_out,
|
||||
size_t buffer_size,
|
||||
git_buf *out,
|
||||
git_repository *repo,
|
||||
const char *canonical_branch_name);
|
||||
|
||||
|
@ -43,17 +43,17 @@ GIT_BEGIN_DECL
|
||||
* In between those are `GIT_CHECKOUT_SAFE` and `GIT_CHECKOUT_SAFE_CREATE`
|
||||
* both of which only make modifications that will not lose changes.
|
||||
*
|
||||
* | target == baseline | target != baseline |
|
||||
* ---------------------|-----------------------|----------------------|
|
||||
* workdir == baseline | no action | create, update, or |
|
||||
* | | delete file |
|
||||
* ---------------------|-----------------------|----------------------|
|
||||
* workdir exists and | no action | conflict (notify |
|
||||
* is != baseline | notify dirty MODIFIED | and cancel checkout) |
|
||||
* ---------------------|-----------------------|----------------------|
|
||||
* workdir missing, | create if SAFE_CREATE | create file |
|
||||
* baseline present | notify dirty DELETED | |
|
||||
* ---------------------|-----------------------|----------------------|
|
||||
* | target == baseline | target != baseline |
|
||||
* ---------------------|-----------------------|----------------------|
|
||||
* workdir == baseline | no action | create, update, or |
|
||||
* | | delete file |
|
||||
* ---------------------|-----------------------|----------------------|
|
||||
* workdir exists and | no action | conflict (notify |
|
||||
* is != baseline | notify dirty MODIFIED | and cancel checkout) |
|
||||
* ---------------------|-----------------------|----------------------|
|
||||
* workdir missing, | create if SAFE_CREATE | create file |
|
||||
* baseline present | notify dirty DELETED | |
|
||||
* ---------------------|-----------------------|----------------------|
|
||||
*
|
||||
* The only difference between SAFE and SAFE_CREATE is that SAFE_CREATE
|
||||
* will cause a file to be checked out if it is missing from the working
|
||||
@ -99,9 +99,14 @@ GIT_BEGIN_DECL
|
||||
* files with unmerged index entries instead. GIT_CHECKOUT_USE_OURS and
|
||||
* GIT_CHECKOUT_USE_THEIRS to proceed with the checkout using either the
|
||||
* stage 2 ("ours") or stage 3 ("theirs") version of files in the index.
|
||||
*
|
||||
* - GIT_CHECKOUT_DONT_OVERWRITE_IGNORED prevents ignored files from being
|
||||
* overwritten. Normally, files that are ignored in the working directory
|
||||
* are not considered "precious" and may be overwritten if the checkout
|
||||
* target contains that file.
|
||||
*/
|
||||
typedef enum {
|
||||
GIT_CHECKOUT_NONE = 0, /** default is a dry run, no actual updates */
|
||||
GIT_CHECKOUT_NONE = 0, /**< default is a dry run, no actual updates */
|
||||
|
||||
/** Allow safe updates that cannot overwrite uncommitted data */
|
||||
GIT_CHECKOUT_SAFE = (1u << 0),
|
||||
@ -144,6 +149,15 @@ typedef enum {
|
||||
/** Ignore directories in use, they will be left empty */
|
||||
GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES = (1u << 18),
|
||||
|
||||
/** Don't overwrite ignored files that exist in the checkout target */
|
||||
GIT_CHECKOUT_DONT_OVERWRITE_IGNORED = (1u << 19),
|
||||
|
||||
/** Write normal merge files for conflicts */
|
||||
GIT_CHECKOUT_CONFLICT_STYLE_MERGE = (1u << 20),
|
||||
|
||||
/** Include common ancestor data in diff3 format files for conflicts */
|
||||
GIT_CHECKOUT_CONFLICT_STYLE_DIFF3 = (1u << 21),
|
||||
|
||||
/**
|
||||
* THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED
|
||||
*/
|
||||
@ -174,7 +188,12 @@ typedef enum {
|
||||
* - GIT_CHECKOUT_NOTIFY_IGNORED notifies about ignored files.
|
||||
*
|
||||
* Returning a non-zero value from this callback will cancel the checkout.
|
||||
* Notification callbacks are made prior to modifying any files on disk.
|
||||
* The non-zero return value will be propagated back and returned by the
|
||||
* git_checkout_... call.
|
||||
*
|
||||
* Notification callbacks are made prior to modifying any files on disk,
|
||||
* so canceling on any notification will still happen prior to any files
|
||||
* being modified.
|
||||
*/
|
||||
typedef enum {
|
||||
GIT_CHECKOUT_NOTIFY_NONE = 0,
|
||||
@ -206,12 +225,12 @@ typedef void (*git_checkout_progress_cb)(
|
||||
/**
|
||||
* Checkout options structure
|
||||
*
|
||||
* Zero out for defaults. Initialize with `GIT_CHECKOUT_OPTS_INIT` macro to
|
||||
* Zero out for defaults. Initialize with `GIT_CHECKOUT_OPTIONS_INIT` macro to
|
||||
* correctly set the `version` field. E.g.
|
||||
*
|
||||
* git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT;
|
||||
* git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
|
||||
*/
|
||||
typedef struct git_checkout_opts {
|
||||
typedef struct git_checkout_options {
|
||||
unsigned int version;
|
||||
|
||||
unsigned int checkout_strategy; /** default will be a dry run */
|
||||
@ -239,12 +258,25 @@ typedef struct git_checkout_opts {
|
||||
|
||||
const char *target_directory; /** alternative checkout path to workdir */
|
||||
|
||||
const char *ancestor_label; /** the name of the common ancestor side of conflicts */
|
||||
const char *our_label; /** the name of the "our" side of conflicts */
|
||||
const char *their_label; /** the name of the "their" side of conflicts */
|
||||
} git_checkout_opts;
|
||||
} git_checkout_options;
|
||||
|
||||
#define GIT_CHECKOUT_OPTS_VERSION 1
|
||||
#define GIT_CHECKOUT_OPTS_INIT {GIT_CHECKOUT_OPTS_VERSION}
|
||||
#define GIT_CHECKOUT_OPTIONS_VERSION 1
|
||||
#define GIT_CHECKOUT_OPTIONS_INIT {GIT_CHECKOUT_OPTIONS_VERSION}
|
||||
|
||||
/**
|
||||
* Initializes a `git_checkout_options` with default values. Equivalent to
|
||||
* creating an instance with GIT_CHECKOUT_OPTIONS_INIT.
|
||||
*
|
||||
* @param opts the `git_checkout_options` struct to initialize.
|
||||
* @param version Version of struct; pass `GIT_CHECKOUT_OPTIONS_VERSION`
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_checkout_init_options(
|
||||
git_checkout_options *opts,
|
||||
unsigned int version);
|
||||
|
||||
/**
|
||||
* Updates files in the index and the working tree to match the content of
|
||||
@ -252,13 +284,13 @@ typedef struct git_checkout_opts {
|
||||
*
|
||||
* @param repo repository to check out (must be non-bare)
|
||||
* @param opts specifies checkout options (may be NULL)
|
||||
* @return 0 on success, GIT_EUNBORNBRANCH when HEAD points to a non existing
|
||||
* branch, GIT_ERROR otherwise (use giterr_last for information
|
||||
* about the error)
|
||||
* @return 0 on success, GIT_EUNBORNBRANCH if HEAD points to a non
|
||||
* existing branch, non-zero value returned by `notify_cb`, or
|
||||
* other error code < 0 (use giterr_last for error details)
|
||||
*/
|
||||
GIT_EXTERN(int) git_checkout_head(
|
||||
git_repository *repo,
|
||||
const git_checkout_opts *opts);
|
||||
const git_checkout_options *opts);
|
||||
|
||||
/**
|
||||
* Updates files in the working tree to match the content of the index.
|
||||
@ -266,13 +298,13 @@ GIT_EXTERN(int) git_checkout_head(
|
||||
* @param repo repository into which to check out (must be non-bare)
|
||||
* @param index index to be checked out (or NULL to use repository index)
|
||||
* @param opts specifies checkout options (may be NULL)
|
||||
* @return 0 on success, GIT_ERROR otherwise (use giterr_last for information
|
||||
* about the error)
|
||||
* @return 0 on success, non-zero return value from `notify_cb`, or error
|
||||
* code < 0 (use giterr_last for error details)
|
||||
*/
|
||||
GIT_EXTERN(int) git_checkout_index(
|
||||
git_repository *repo,
|
||||
git_index *index,
|
||||
const git_checkout_opts *opts);
|
||||
const git_checkout_options *opts);
|
||||
|
||||
/**
|
||||
* Updates files in the index and working tree to match the content of the
|
||||
@ -282,13 +314,13 @@ GIT_EXTERN(int) git_checkout_index(
|
||||
* @param treeish a commit, tag or tree which content will be used to update
|
||||
* the working directory (or NULL to use HEAD)
|
||||
* @param opts specifies checkout options (may be NULL)
|
||||
* @return 0 on success, GIT_ERROR otherwise (use giterr_last for information
|
||||
* about the error)
|
||||
* @return 0 on success, non-zero return value from `notify_cb`, or error
|
||||
* code < 0 (use giterr_last for error details)
|
||||
*/
|
||||
GIT_EXTERN(int) git_checkout_tree(
|
||||
git_repository *repo,
|
||||
const git_object *treeish,
|
||||
const git_checkout_opts *opts);
|
||||
const git_checkout_options *opts);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
|
87
include/git2/cherrypick.h
Normal file
87
include/git2/cherrypick.h
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) the libgit2 contributors. All rights reserved.
|
||||
*
|
||||
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
||||
* a Linking Exception. For full terms see the included COPYING file.
|
||||
*/
|
||||
#ifndef INCLUDE_git_cherrypick_h__
|
||||
#define INCLUDE_git_cherrypick_h__
|
||||
|
||||
#include "common.h"
|
||||
#include "types.h"
|
||||
#include "merge.h"
|
||||
|
||||
/**
|
||||
* @file git2/cherrypick.h
|
||||
* @brief Git cherry-pick routines
|
||||
* @defgroup git_cherrypick Git cherry-pick routines
|
||||
* @ingroup Git
|
||||
* @{
|
||||
*/
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
|
||||
/** For merge commits, the "mainline" is treated as the parent. */
|
||||
unsigned int mainline;
|
||||
|
||||
git_merge_options merge_opts;
|
||||
git_checkout_options checkout_opts;
|
||||
} git_cherry_pick_options;
|
||||
|
||||
#define GIT_CHERRY_PICK_OPTIONS_VERSION 1
|
||||
#define GIT_CHERRY_PICK_OPTIONS_INIT {GIT_CHERRY_PICK_OPTIONS_VERSION, 0, GIT_MERGE_OPTIONS_INIT, GIT_CHECKOUT_OPTIONS_INIT}
|
||||
|
||||
/**
|
||||
* Initializes a `git_cherry_pick_options` with default values. Equivalent to
|
||||
* creating an instance with GIT_CHERRY_PICK_OPTIONS_INIT.
|
||||
*
|
||||
* @param opts the `git_cherry_pick_options` struct to initialize
|
||||
* @param version Version of struct; pass `GIT_CHERRY_PICK_OPTIONS_VERSION`
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_cherry_pick_init_options(
|
||||
git_cherry_pick_options *opts,
|
||||
unsigned int version);
|
||||
|
||||
/**
|
||||
* Cherry-picks the given commit against the given "our" commit, producing an
|
||||
* index that reflects the result of the cherry-pick.
|
||||
*
|
||||
* The returned index must be freed explicitly with `git_index_free`.
|
||||
*
|
||||
* @param out pointer to store the index result in
|
||||
* @param repo the repository that contains the given commits
|
||||
* @param cherry_pick_commit the commit to cherry-pick
|
||||
* @param our_commit the commit to revert against (eg, HEAD)
|
||||
* @param mainline the parent of the revert commit, if it is a merge
|
||||
* @param merge_options the merge options (or null for defaults)
|
||||
* @return zero on success, -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_cherry_pick_commit(
|
||||
git_index **out,
|
||||
git_repository *repo,
|
||||
git_commit *cherry_pick_commit,
|
||||
git_commit *our_commit,
|
||||
unsigned int mainline,
|
||||
const git_merge_options *merge_options);
|
||||
|
||||
/**
|
||||
* Cherry-pick the given commit, producing changes in the index and working directory.
|
||||
*
|
||||
* @param repo the repository to cherry-pick
|
||||
* @param commit the commit to cherry-pick
|
||||
* @param cherry_pick_options the cherry-pick options (or null for defaults)
|
||||
* @return zero on success, -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_cherry_pick(
|
||||
git_repository *repo,
|
||||
git_commit *commit,
|
||||
const git_cherry_pick_options *cherry_pick_options);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
|
||||
#endif
|
||||
|
@ -23,42 +23,109 @@
|
||||
*/
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Options for bypassing the git-aware transport on clone. Bypassing
|
||||
* it means that instead of a fetch, libgit2 will copy the object
|
||||
* database directory instead of figuring out what it needs, which is
|
||||
* faster. If possible, it will hardlink the files to save space.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* Auto-detect (default), libgit2 will bypass the git-aware
|
||||
* transport for local paths, but use a normal fetch for
|
||||
* `file://` urls.
|
||||
*/
|
||||
GIT_CLONE_LOCAL_AUTO,
|
||||
/**
|
||||
* Bypass the git-aware transport even for a `file://` url.
|
||||
*/
|
||||
GIT_CLONE_LOCAL,
|
||||
/**
|
||||
* Do no bypass the git-aware transport
|
||||
*/
|
||||
GIT_CLONE_NO_LOCAL,
|
||||
/**
|
||||
* Bypass the git-aware transport, but do not try to use
|
||||
* hardlinks.
|
||||
*/
|
||||
GIT_CLONE_LOCAL_NO_LINKS,
|
||||
} git_clone_local_t;
|
||||
|
||||
/**
|
||||
* Clone options structure
|
||||
*
|
||||
* Use zeros to indicate default settings. It's easiest to use the
|
||||
* `GIT_CLONE_OPTIONS_INIT` macro:
|
||||
* Use the GIT_CLONE_OPTIONS_INIT to get the default settings, like this:
|
||||
*
|
||||
* git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
|
||||
*
|
||||
* - `checkout_opts` is options for the checkout step. To disable checkout,
|
||||
* set the `checkout_strategy` to GIT_CHECKOUT_DEFAULT.
|
||||
* - `bare` should be set to zero to create a standard repo, non-zero for
|
||||
* a bare repo
|
||||
* - `ignore_cert_errors` should be set to 1 if errors validating the remote host's
|
||||
* certificate should be ignored.
|
||||
*
|
||||
* ** "origin" remote options: **
|
||||
* - `remote_name` is the name given to the "origin" remote. The default is
|
||||
* "origin".
|
||||
* - `checkout_branch` gives the name of the branch to checkout. NULL means
|
||||
* use the remote's HEAD.
|
||||
*/
|
||||
|
||||
typedef struct git_clone_options {
|
||||
unsigned int version;
|
||||
|
||||
git_checkout_opts checkout_opts;
|
||||
/**
|
||||
* These options are passed to the checkout step. To disable
|
||||
* checkout, set the `checkout_strategy` to
|
||||
* `GIT_CHECKOUT_NONE`. Generally you will want the use
|
||||
* GIT_CHECKOUT_SAFE_CREATE to create all files in the working
|
||||
* directory for the newly cloned repository.
|
||||
*/
|
||||
git_checkout_options checkout_opts;
|
||||
|
||||
/**
|
||||
* Callbacks to use for reporting fetch progress.
|
||||
*/
|
||||
git_remote_callbacks remote_callbacks;
|
||||
|
||||
/**
|
||||
* Set to zero (false) to create a standard repo, or non-zero
|
||||
* for a bare repo
|
||||
*/
|
||||
int bare;
|
||||
|
||||
/**
|
||||
* Set to 1 if errors validating the remote host's certificate
|
||||
* should be ignored.
|
||||
*/
|
||||
int ignore_cert_errors;
|
||||
|
||||
/**
|
||||
* Whether to use a fetch or copy the object database.
|
||||
*/
|
||||
git_clone_local_t local;
|
||||
|
||||
/**
|
||||
* The name to be given to the remote that will be
|
||||
* created. The default is "origin".
|
||||
*/
|
||||
const char *remote_name;
|
||||
|
||||
/**
|
||||
* The name of the branch to checkout. NULL means use the
|
||||
* remote's default branch.
|
||||
*/
|
||||
const char* checkout_branch;
|
||||
|
||||
/**
|
||||
* The identity used when updating the reflog. NULL means to
|
||||
* use the default signature using the config.
|
||||
*/
|
||||
git_signature *signature;
|
||||
} git_clone_options;
|
||||
|
||||
#define GIT_CLONE_OPTIONS_VERSION 1
|
||||
#define GIT_CLONE_OPTIONS_INIT {GIT_CLONE_OPTIONS_VERSION, {GIT_CHECKOUT_OPTS_VERSION, GIT_CHECKOUT_SAFE_CREATE}, GIT_REMOTE_CALLBACKS_INIT}
|
||||
#define GIT_CLONE_OPTIONS_INIT {GIT_CLONE_OPTIONS_VERSION, {GIT_CHECKOUT_OPTIONS_VERSION, GIT_CHECKOUT_SAFE_CREATE}, GIT_REMOTE_CALLBACKS_INIT}
|
||||
|
||||
/**
|
||||
* Initializes a `git_clone_options` with default values. Equivalent to
|
||||
* creating an instance with GIT_CLONE_OPTIONS_INIT.
|
||||
*
|
||||
* @param opts The `git_clone_options` struct to initialize
|
||||
* @param version Version of struct; pass `GIT_CLONE_OPTIONS_VERSION`
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_clone_init_options(
|
||||
git_clone_options *opts,
|
||||
unsigned int version);
|
||||
|
||||
/**
|
||||
* Clone a remote repository.
|
||||
@ -70,16 +137,17 @@ typedef struct git_clone_options {
|
||||
* @param out pointer that will receive the resulting repository object
|
||||
* @param url the remote repository to clone
|
||||
* @param local_path local directory to clone to
|
||||
* @param options configuration options for the clone. If NULL, the function
|
||||
* works as though GIT_OPTIONS_INIT were passed.
|
||||
* @return 0 on success, GIT_ERROR otherwise (use giterr_last for information
|
||||
* about the error)
|
||||
* @param options configuration options for the clone. If NULL, the
|
||||
* function works as though GIT_OPTIONS_INIT were passed.
|
||||
* @return 0 on success, any non-zero return value from a callback
|
||||
* function, or a negative value to indicate an error (use
|
||||
* `giterr_last` for a detailed error message)
|
||||
*/
|
||||
GIT_EXTERN(int) git_clone(
|
||||
git_repository **out,
|
||||
const char *url,
|
||||
const char *local_path,
|
||||
const git_clone_options *options);
|
||||
git_repository **out,
|
||||
const char *url,
|
||||
const char *local_path,
|
||||
const git_clone_options *options);
|
||||
|
||||
/**
|
||||
* Clone into a repository
|
||||
@ -91,11 +159,48 @@ GIT_EXTERN(int) git_clone(
|
||||
* @param repo the repository to use
|
||||
* @param remote the remote repository to clone from
|
||||
* @param co_opts options to use during checkout
|
||||
* @param branch the branch to checkout after the clone, pass NULL for the remote's
|
||||
* default branch
|
||||
* @return 0 on success or an error code
|
||||
* @param branch the branch to checkout after the clone, pass NULL for the
|
||||
* remote's default branch
|
||||
* @param signature The identity used when updating the reflog.
|
||||
* @return 0 on success, any non-zero return value from a callback
|
||||
* function, or a negative value to indicate an error (use
|
||||
* `giterr_last` for a detailed error message)
|
||||
*/
|
||||
GIT_EXTERN(int) git_clone_into(git_repository *repo, git_remote *remote, const git_checkout_opts *co_opts, const char *branch);
|
||||
GIT_EXTERN(int) git_clone_into(
|
||||
git_repository *repo,
|
||||
git_remote *remote,
|
||||
const git_checkout_options *co_opts,
|
||||
const char *branch,
|
||||
const git_signature *signature);
|
||||
|
||||
/**
|
||||
* Perform a local clone into a repository
|
||||
*
|
||||
* A "local clone" bypasses any git-aware protocols and simply copies
|
||||
* over the object database from the source repository. It is often
|
||||
* faster than a git-aware clone, but no verification of the data is
|
||||
* performed, and can copy over too much data.
|
||||
*
|
||||
* @param repo the repository to use
|
||||
* @param remote the remote repository to clone from
|
||||
* @param co_opts options to use during checkout
|
||||
* @param branch the branch to checkout after the clone, pass NULL for the
|
||||
* remote's default branch
|
||||
* @param link wether to use hardlinks instead of copying
|
||||
* objects. This is only possible if both repositories are on the same
|
||||
* filesystem.
|
||||
* @param signature the identity used when updating the reflog
|
||||
* @return 0 on success, any non-zero return value from a callback
|
||||
* function, or a negative value to indicate an error (use
|
||||
* `giterr_last` for a detailed error message)
|
||||
*/
|
||||
GIT_EXTERN(int) git_clone_local_into(
|
||||
git_repository *repo,
|
||||
git_remote *remote,
|
||||
const git_checkout_options *co_opts,
|
||||
const char *branch,
|
||||
int link,
|
||||
const git_signature *signature);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
|
@ -116,6 +116,17 @@ GIT_EXTERN(const char *) git_commit_message(const git_commit *commit);
|
||||
*/
|
||||
GIT_EXTERN(const char *) git_commit_message_raw(const git_commit *commit);
|
||||
|
||||
/**
|
||||
* Get the short "summary" of the git commit message.
|
||||
*
|
||||
* The returned message is the summary of the commit, comprising the
|
||||
* first paragraph of the message with whitespace trimmed and squashed.
|
||||
*
|
||||
* @param commit a previously loaded commit.
|
||||
* @return the summary of a commit or NULL on error
|
||||
*/
|
||||
GIT_EXTERN(const char *) git_commit_summary(git_commit *commit);
|
||||
|
||||
/**
|
||||
* Get the commit time (i.e. committer time) of a commit.
|
||||
*
|
||||
@ -231,8 +242,8 @@ GIT_EXTERN(int) git_commit_nth_gen_ancestor(
|
||||
/**
|
||||
* Create new commit in the repository from a list of `git_object` pointers
|
||||
*
|
||||
* The message will not be cleaned up automatically. You can do that with
|
||||
* the `git_message_prettify()` function.
|
||||
* The message will **not** be cleaned up automatically. You can do that
|
||||
* with the `git_message_prettify()` function.
|
||||
*
|
||||
* @param id Pointer in which to store the OID of the newly created commit
|
||||
*
|
||||
@ -243,7 +254,8 @@ GIT_EXTERN(int) git_commit_nth_gen_ancestor(
|
||||
* is not direct, it will be resolved to a direct reference.
|
||||
* Use "HEAD" to update the HEAD of the current branch and
|
||||
* make it point to this commit. If the reference doesn't
|
||||
* exist yet, it will be created.
|
||||
* exist yet, it will be created. If it does exist, the first
|
||||
* parent must be the tip of this branch.
|
||||
*
|
||||
* @param author Signature with author and author time of commit
|
||||
*
|
||||
@ -280,20 +292,20 @@ GIT_EXTERN(int) git_commit_create(
|
||||
const char *message_encoding,
|
||||
const char *message,
|
||||
const git_tree *tree,
|
||||
int parent_count,
|
||||
size_t parent_count,
|
||||
const git_commit *parents[]);
|
||||
|
||||
/**
|
||||
* Create new commit in the repository using a variable argument list.
|
||||
*
|
||||
* The message will be cleaned up from excess whitespace and it will be made
|
||||
* sure that the last line ends with a '\n'.
|
||||
* The message will **not** be cleaned up automatically. You can do that
|
||||
* with the `git_message_prettify()` function.
|
||||
*
|
||||
* The parents for the commit are specified as a variable list of pointers
|
||||
* to `const git_commit *`. Note that this is a convenience method which may
|
||||
* not be safe to export for certain languages or compilers
|
||||
*
|
||||
* All other parameters remain the same at `git_commit_create()`.
|
||||
* All other parameters remain the same as `git_commit_create()`.
|
||||
*
|
||||
* @see git_commit_create
|
||||
*/
|
||||
@ -306,9 +318,40 @@ GIT_EXTERN(int) git_commit_create_v(
|
||||
const char *message_encoding,
|
||||
const char *message,
|
||||
const git_tree *tree,
|
||||
int parent_count,
|
||||
size_t parent_count,
|
||||
...);
|
||||
|
||||
/**
|
||||
* Amend an existing commit by replacing only non-NULL values.
|
||||
*
|
||||
* This creates a new commit that is exactly the same as the old commit,
|
||||
* except that any non-NULL values will be updated. The new commit has
|
||||
* the same parents as the old commit.
|
||||
*
|
||||
* The `update_ref` value works as in the regular `git_commit_create()`,
|
||||
* updating the ref to point to the newly rewritten commit. If you want
|
||||
* to amend a commit that is not currently the tip of the branch and then
|
||||
* rewrite the following commits to reach a ref, pass this as NULL and
|
||||
* update the rest of the commit chain and ref separately.
|
||||
*
|
||||
* Unlike `git_commit_create()`, the `author`, `committer`, `message`,
|
||||
* `message_encoding`, and `tree` parameters can be NULL in which case this
|
||||
* will use the values from the original `commit_to_amend`.
|
||||
*
|
||||
* All parameters have the same meanings as in `git_commit_create()`.
|
||||
*
|
||||
* @see git_commit_create
|
||||
*/
|
||||
GIT_EXTERN(int) git_commit_amend(
|
||||
git_oid *id,
|
||||
const git_commit *commit_to_amend,
|
||||
const char *update_ref,
|
||||
const git_signature *author,
|
||||
const git_signature *committer,
|
||||
const char *message_encoding,
|
||||
const char *message,
|
||||
const git_tree *tree);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
#endif
|
||||
|
@ -37,13 +37,6 @@
|
||||
# define GIT_EXTERN(type) extern type
|
||||
#endif
|
||||
|
||||
/** Declare a function as always inlined. */
|
||||
#if defined(_MSC_VER)
|
||||
# define GIT_INLINE(type) static __inline type
|
||||
#else
|
||||
# define GIT_INLINE(type) static inline type
|
||||
#endif
|
||||
|
||||
/** Declare a function's takes printf style arguments. */
|
||||
#ifdef __GNUC__
|
||||
# define GIT_FORMAT_PRINTF(a,b) __attribute__((format (printf, a, b)))
|
||||
@ -101,29 +94,34 @@ GIT_BEGIN_DECL
|
||||
GIT_EXTERN(void) git_libgit2_version(int *major, int *minor, int *rev);
|
||||
|
||||
/**
|
||||
* Combinations of these values describe the capabilities of libgit2.
|
||||
* Combinations of these values describe the features with which libgit2
|
||||
* was compiled
|
||||
*/
|
||||
typedef enum {
|
||||
GIT_CAP_THREADS = ( 1 << 0 ),
|
||||
GIT_CAP_HTTPS = ( 1 << 1 ),
|
||||
GIT_CAP_SSH = ( 1 << 2 ),
|
||||
} git_cap_t;
|
||||
GIT_FEATURE_THREADS = (1 << 0),
|
||||
GIT_FEATURE_HTTPS = (1 << 1),
|
||||
GIT_FEATURE_SSH = (1 << 2),
|
||||
} git_feature_t;
|
||||
|
||||
/**
|
||||
* Query compile time options for libgit2.
|
||||
*
|
||||
* @return A combination of GIT_CAP_* values.
|
||||
* @return A combination of GIT_FEATURE_* values.
|
||||
*
|
||||
* - GIT_CAP_THREADS
|
||||
* - GIT_FEATURE_THREADS
|
||||
* Libgit2 was compiled with thread support. Note that thread support is
|
||||
* still to be seen as a 'work in progress' - basic object lookups are
|
||||
* believed to be threadsafe, but other operations may not be.
|
||||
*
|
||||
* - GIT_CAP_HTTPS
|
||||
* - GIT_FEATURE_HTTPS
|
||||
* Libgit2 supports the https:// protocol. This requires the openssl
|
||||
* library to be found when compiling libgit2.
|
||||
*
|
||||
* - GIT_FEATURE_SSH
|
||||
* Libgit2 supports the SSH protocol for network operations. This requires
|
||||
* the libssh2 library to be found when compiling libgit2
|
||||
*/
|
||||
GIT_EXTERN(int) git_libgit2_capabilities(void);
|
||||
GIT_EXTERN(int) git_libgit2_features(void);
|
||||
|
||||
|
||||
typedef enum {
|
||||
@ -163,12 +161,12 @@ typedef enum {
|
||||
* >Set the maximum amount of memory that can be mapped at any time
|
||||
* by the library
|
||||
*
|
||||
* * opts(GIT_OPT_GET_SEARCH_PATH, int level, char *out, size_t len)
|
||||
* * opts(GIT_OPT_GET_SEARCH_PATH, int level, git_buf *buf)
|
||||
*
|
||||
* > Get the search path for a given level of config data. "level" must
|
||||
* > be one of `GIT_CONFIG_LEVEL_SYSTEM`, `GIT_CONFIG_LEVEL_GLOBAL`, or
|
||||
* > `GIT_CONFIG_LEVEL_XDG`. The search path is written to the `out`
|
||||
* > buffer up to size `len`. Returns GIT_EBUFS if buffer is too small.
|
||||
* > buffer.
|
||||
*
|
||||
* * opts(GIT_OPT_SET_SEARCH_PATH, int level, const char *path)
|
||||
*
|
||||
@ -197,7 +195,7 @@ typedef enum {
|
||||
* > across all repositories before libgit2 starts evicting objects
|
||||
* > from the cache. This is a soft limit, in that the library might
|
||||
* > briefly exceed it, but will start aggressively evicting objects
|
||||
* > from cache when that happens. The default cache size is 256Mb.
|
||||
* > from cache when that happens. The default cache size is 256MB.
|
||||
*
|
||||
* * opts(GIT_OPT_ENABLE_CACHING, int enabled)
|
||||
*
|
||||
@ -212,11 +210,10 @@ typedef enum {
|
||||
* > Get the current bytes in cache and the maximum that would be
|
||||
* > allowed in the cache.
|
||||
*
|
||||
* * opts(GIT_OPT_GET_TEMPLATE_PATH, char *out, size_t len)
|
||||
* * opts(GIT_OPT_GET_TEMPLATE_PATH, git_buf *out)
|
||||
*
|
||||
* > Get the default template path.
|
||||
* > The path is written to the `out`
|
||||
* > buffer up to size `len`. Returns GIT_EBUFS if buffer is too small.
|
||||
* > The path is written to the `out` buffer.
|
||||
*
|
||||
* * opts(GIT_OPT_SET_TEMPLATE_PATH, const char *path)
|
||||
*
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "types.h"
|
||||
#include "buffer.h"
|
||||
|
||||
/**
|
||||
* @file git2/config.h
|
||||
@ -90,11 +91,10 @@ typedef struct {
|
||||
* This method will not guess the path to the xdg compatible
|
||||
* config file (.config/git/config).
|
||||
*
|
||||
* @param out Buffer to store the path in
|
||||
* @param length size of the buffer in bytes
|
||||
* @return 0 if a global configuration file has been found. Its path will be stored in `buffer`.
|
||||
* @param out Pointer to a user-allocated git_buf in which to store the path
|
||||
* @return 0 if a global configuration file has been found. Its path will be stored in `out`.
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_find_global(char *out, size_t length);
|
||||
GIT_EXTERN(int) git_config_find_global(git_buf *out);
|
||||
|
||||
/**
|
||||
* Locate the path to the global xdg compatible configuration file
|
||||
@ -107,25 +107,23 @@ GIT_EXTERN(int) git_config_find_global(char *out, size_t length);
|
||||
* may be used on any `git_config` call to load the
|
||||
* xdg compatible configuration file.
|
||||
*
|
||||
* @param out Buffer to store the path in
|
||||
* @param length size of the buffer in bytes
|
||||
* @param out Pointer to a user-allocated git_buf in which to store the path
|
||||
* @return 0 if a xdg compatible configuration file has been
|
||||
* found. Its path will be stored in `buffer`.
|
||||
* found. Its path will be stored in `out`.
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_find_xdg(char *out, size_t length);
|
||||
GIT_EXTERN(int) git_config_find_xdg(git_buf *out);
|
||||
|
||||
/**
|
||||
* Locate the path to the system configuration file
|
||||
*
|
||||
* If /etc/gitconfig doesn't exist, it will look for
|
||||
* %PROGRAMFILES%\Git\etc\gitconfig.
|
||||
|
||||
* @param out Buffer to store the path in
|
||||
* @param length size of the buffer in bytes
|
||||
*
|
||||
* @param out Pointer to a user-allocated git_buf in which to store the path
|
||||
* @return 0 if a system configuration file has been
|
||||
* found. Its path will be stored in `buffer`.
|
||||
* found. Its path will be stored in `out`.
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_find_system(char *out, size_t length);
|
||||
GIT_EXTERN(int) git_config_find_system(git_buf *out);
|
||||
|
||||
/**
|
||||
* Open the global, XDG and system configuration files
|
||||
@ -228,6 +226,22 @@ GIT_EXTERN(int) git_config_open_level(
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_open_global(git_config **out, git_config *config);
|
||||
|
||||
/**
|
||||
* Create a snapshot of the configuration
|
||||
*
|
||||
* Create a snapshot of the current state of a configuration, which
|
||||
* allows you to look into a consistent view of the configuration for
|
||||
* looking up complex values (e.g. a remote, submodule).
|
||||
*
|
||||
* The string returned when querying such a config object is valid
|
||||
* until it is freed.
|
||||
*
|
||||
* @param out pointer in which to store the snapshot config object
|
||||
* @param config configuration to snapshot
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_snapshot(git_config **out, git_config *config);
|
||||
|
||||
|
||||
/**
|
||||
* Reload changed config files
|
||||
@ -314,7 +328,8 @@ GIT_EXTERN(int) git_config_get_bool(int *out, const git_config *cfg, const char
|
||||
* Get the value of a string config variable.
|
||||
*
|
||||
* The string is owned by the variable and should not be freed by the
|
||||
* user.
|
||||
* user. The pointer will be valid until the next operation on this
|
||||
* config object.
|
||||
*
|
||||
* All config files will be looked into, in the order of their
|
||||
* defined level. A higher level means a higher priority. The
|
||||
@ -355,6 +370,9 @@ GIT_EXTERN(int) git_config_multivar_iterator_new(git_config_iterator **out, cons
|
||||
/**
|
||||
* Return the current entry and advance the iterator
|
||||
*
|
||||
* The pointers returned by this function are valid until the iterator
|
||||
* is freed.
|
||||
*
|
||||
* @param entry pointer to store the entry
|
||||
* @param iter the iterator
|
||||
* @return 0 or an error code. GIT_ITEROVER if the iteration has completed
|
||||
@ -450,13 +468,16 @@ GIT_EXTERN(int) git_config_delete_multivar(git_config *cfg, const char *name, co
|
||||
*
|
||||
* The callback receives the normalized name and value of each variable
|
||||
* in the config backend, and the data pointer passed to this function.
|
||||
* As soon as one of the callback functions returns something other than 0,
|
||||
* this function stops iterating and returns `GIT_EUSER`.
|
||||
* If the callback returns a non-zero value, the function stops iterating
|
||||
* and returns that value to the caller.
|
||||
*
|
||||
* The pointers passed to the callback are only valid as long as the
|
||||
* iteration is ongoing.
|
||||
*
|
||||
* @param cfg where to get the variables from
|
||||
* @param callback the function to call on each variable
|
||||
* @param payload the data to pass to the callback
|
||||
* @return 0 on success, GIT_EUSER on non-zero callback, or error code
|
||||
* @return 0 on success, non-zero callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_foreach(
|
||||
const git_config *cfg,
|
||||
@ -493,6 +514,9 @@ GIT_EXTERN(int) git_config_iterator_glob_new(git_config_iterator **out, const gi
|
||||
* regular expression that filters which config keys are passed to the
|
||||
* callback.
|
||||
*
|
||||
* The pointers passed to the callback are only valid as long as the
|
||||
* iteration is ongoing.
|
||||
*
|
||||
* @param cfg where to get the variables from
|
||||
* @param regexp regular expression to match against config names
|
||||
* @param callback the function to call on each variable
|
||||
@ -612,8 +636,8 @@ GIT_EXTERN(int) git_config_parse_int64(int64_t *out, const char *value);
|
||||
GIT_EXTERN(int) git_config_backend_foreach_match(
|
||||
git_config_backend *backend,
|
||||
const char *regexp,
|
||||
int (*fn)(const git_config_entry *, void *),
|
||||
void *data);
|
||||
git_config_foreach_cb callback,
|
||||
void *payload);
|
||||
|
||||
|
||||
/** @} */
|
||||
|
@ -145,6 +145,13 @@ typedef enum {
|
||||
*/
|
||||
GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS = (1u << 14),
|
||||
|
||||
/** When diff finds a file in the working directory with stat
|
||||
* information different from the index, but the OID ends up being the
|
||||
* same, write the correct stat information into the index. Note:
|
||||
* without this flag, diff will always leave the index untouched.
|
||||
*/
|
||||
GIT_DIFF_UPDATE_INDEX = (1u << 15),
|
||||
|
||||
/*
|
||||
* Options controlling how output will be generated
|
||||
*/
|
||||
@ -180,6 +187,10 @@ typedef enum {
|
||||
/** Take extra time to find minimal diff */
|
||||
GIT_DIFF_MINIMAL = (1 << 29),
|
||||
|
||||
/** Include the necessary deflate / delta information so that `git-apply`
|
||||
* can apply given diff information to binary files.
|
||||
*/
|
||||
GIT_DIFF_SHOW_BINARY = (1 << 30),
|
||||
} git_diff_option_t;
|
||||
|
||||
/**
|
||||
@ -201,9 +212,9 @@ typedef struct git_diff git_diff;
|
||||
* considered reserved for internal or future use.
|
||||
*/
|
||||
typedef enum {
|
||||
GIT_DIFF_FLAG_BINARY = (1u << 0), /** file(s) treated as binary data */
|
||||
GIT_DIFF_FLAG_NOT_BINARY = (1u << 1), /** file(s) treated as text data */
|
||||
GIT_DIFF_FLAG_VALID_OID = (1u << 2), /** `oid` value is known correct */
|
||||
GIT_DIFF_FLAG_BINARY = (1u << 0), /**< file(s) treated as binary data */
|
||||
GIT_DIFF_FLAG_NOT_BINARY = (1u << 1), /**< file(s) treated as text data */
|
||||
GIT_DIFF_FLAG_VALID_ID = (1u << 2), /**< `id` value is known correct */
|
||||
} git_diff_flag_t;
|
||||
|
||||
/**
|
||||
@ -217,15 +228,15 @@ typedef enum {
|
||||
* DELETED pairs).
|
||||
*/
|
||||
typedef enum {
|
||||
GIT_DELTA_UNMODIFIED = 0, /** no changes */
|
||||
GIT_DELTA_ADDED = 1, /** entry does not exist in old version */
|
||||
GIT_DELTA_DELETED = 2, /** entry does not exist in new version */
|
||||
GIT_DELTA_MODIFIED = 3, /** entry content changed between old and new */
|
||||
GIT_DELTA_RENAMED = 4, /** entry was renamed between old and new */
|
||||
GIT_DELTA_COPIED = 5, /** entry was copied from another old entry */
|
||||
GIT_DELTA_IGNORED = 6, /** entry is ignored item in workdir */
|
||||
GIT_DELTA_UNTRACKED = 7, /** entry is untracked item in workdir */
|
||||
GIT_DELTA_TYPECHANGE = 8, /** type of entry changed between old and new */
|
||||
GIT_DELTA_UNMODIFIED = 0, /**< no changes */
|
||||
GIT_DELTA_ADDED = 1, /**< entry does not exist in old version */
|
||||
GIT_DELTA_DELETED = 2, /**< entry does not exist in new version */
|
||||
GIT_DELTA_MODIFIED = 3, /**< entry content changed between old and new */
|
||||
GIT_DELTA_RENAMED = 4, /**< entry was renamed between old and new */
|
||||
GIT_DELTA_COPIED = 5, /**< entry was copied from another old entry */
|
||||
GIT_DELTA_IGNORED = 6, /**< entry is ignored item in workdir */
|
||||
GIT_DELTA_UNTRACKED = 7, /**< entry is untracked item in workdir */
|
||||
GIT_DELTA_TYPECHANGE = 8, /**< type of entry changed between old and new */
|
||||
} git_delta_t;
|
||||
|
||||
/**
|
||||
@ -250,7 +261,7 @@ typedef enum {
|
||||
* be restricted to one of the `git_filemode_t` values.
|
||||
*/
|
||||
typedef struct {
|
||||
git_oid oid;
|
||||
git_oid id;
|
||||
const char *path;
|
||||
git_off_t size;
|
||||
uint32_t flags;
|
||||
@ -361,7 +372,7 @@ typedef struct {
|
||||
|
||||
uint16_t context_lines; /**< defaults to 3 */
|
||||
uint16_t interhunk_lines; /**< defaults to 0 */
|
||||
uint16_t oid_abbrev; /**< default 'core.abbrev' or 7 if unset */
|
||||
uint16_t id_abbrev; /**< default 'core.abbrev' or 7 if unset */
|
||||
git_off_t max_size; /**< defaults to 512MB */
|
||||
const char *old_prefix; /**< defaults to "a" */
|
||||
const char *new_prefix; /**< defaults to "b" */
|
||||
@ -376,6 +387,18 @@ typedef struct {
|
||||
#define GIT_DIFF_OPTIONS_INIT \
|
||||
{GIT_DIFF_OPTIONS_VERSION, 0, GIT_SUBMODULE_IGNORE_DEFAULT, {NULL,0}, NULL, NULL, 3}
|
||||
|
||||
/**
|
||||
* Initializes a `git_diff_options` with default values. Equivalent to
|
||||
* creating an instance with GIT_DIFF_OPTIONS_INIT.
|
||||
*
|
||||
* @param opts The `git_diff_options` struct to initialize
|
||||
* @param version Version of struct; pass `GIT_DIFF_OPTIONS_VERSION`
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_init_options(
|
||||
git_diff_options *opts,
|
||||
unsigned int version);
|
||||
|
||||
/**
|
||||
* When iterating over a diff, callback that will be made per file.
|
||||
*
|
||||
@ -393,12 +416,12 @@ typedef int (*git_diff_file_cb)(
|
||||
*/
|
||||
typedef struct git_diff_hunk git_diff_hunk;
|
||||
struct git_diff_hunk {
|
||||
int old_start; /** Starting line number in old_file */
|
||||
int old_lines; /** Number of lines in old_file */
|
||||
int new_start; /** Starting line number in new_file */
|
||||
int new_lines; /** Number of lines in new_file */
|
||||
size_t header_len; /** Number of bytes in header text */
|
||||
char header[128]; /** Header text, NUL-byte terminated */
|
||||
int old_start; /**< Starting line number in old_file */
|
||||
int old_lines; /**< Number of lines in old_file */
|
||||
int new_start; /**< Starting line number in new_file */
|
||||
int new_lines; /**< Number of lines in new_file */
|
||||
size_t header_len; /**< Number of bytes in header text */
|
||||
char header[128]; /**< Header text, NUL-byte terminated */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -441,13 +464,13 @@ typedef enum {
|
||||
*/
|
||||
typedef struct git_diff_line git_diff_line;
|
||||
struct git_diff_line {
|
||||
char origin; /** A git_diff_line_t value */
|
||||
int old_lineno; /** Line number in old file or -1 for added line */
|
||||
int new_lineno; /** Line number in new file or -1 for deleted line */
|
||||
int num_lines; /** Number of newline characters in content */
|
||||
size_t content_len; /** Number of bytes of data */
|
||||
git_off_t content_offset; /** Offset in the original file to the content */
|
||||
const char *content; /** Pointer to diff text, not NUL-byte terminated */
|
||||
char origin; /**< A git_diff_line_t value */
|
||||
int old_lineno; /**< Line number in old file or -1 for added line */
|
||||
int new_lineno; /**< Line number in new file or -1 for deleted line */
|
||||
int num_lines; /**< Number of newline characters in content */
|
||||
size_t content_len; /**< Number of bytes of data */
|
||||
git_off_t content_offset; /**< Offset in the original file to the content */
|
||||
const char *content; /**< Pointer to diff text, not NUL-byte terminated */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -459,50 +482,83 @@ struct git_diff_line {
|
||||
* of lines of file and hunk headers.
|
||||
*/
|
||||
typedef int (*git_diff_line_cb)(
|
||||
const git_diff_delta *delta, /** delta that contains this data */
|
||||
const git_diff_hunk *hunk, /** hunk containing this data */
|
||||
const git_diff_line *line, /** line data */
|
||||
void *payload); /** user reference data */
|
||||
const git_diff_delta *delta, /**< delta that contains this data */
|
||||
const git_diff_hunk *hunk, /**< hunk containing this data */
|
||||
const git_diff_line *line, /**< line data */
|
||||
void *payload); /**< user reference data */
|
||||
|
||||
/**
|
||||
* Flags to control the behavior of diff rename/copy detection.
|
||||
*/
|
||||
typedef enum {
|
||||
/** look for renames? (`--find-renames`) */
|
||||
/** Obey `diff.renames`. Overridden by any other GIT_DIFF_FIND_... flag. */
|
||||
GIT_DIFF_FIND_BY_CONFIG = 0,
|
||||
|
||||
/** Look for renames? (`--find-renames`) */
|
||||
GIT_DIFF_FIND_RENAMES = (1u << 0),
|
||||
/** consider old side of modified for renames? (`--break-rewrites=N`) */
|
||||
|
||||
/** Consider old side of MODIFIED for renames? (`--break-rewrites=N`) */
|
||||
GIT_DIFF_FIND_RENAMES_FROM_REWRITES = (1u << 1),
|
||||
|
||||
/** look for copies? (a la `--find-copies`) */
|
||||
/** Look for copies? (a la `--find-copies`). */
|
||||
GIT_DIFF_FIND_COPIES = (1u << 2),
|
||||
/** consider unmodified as copy sources? (`--find-copies-harder`) */
|
||||
|
||||
/** Consider UNMODIFIED as copy sources? (`--find-copies-harder`).
|
||||
*
|
||||
* For this to work correctly, use GIT_DIFF_INCLUDE_UNMODIFIED when
|
||||
* the initial `git_diff` is being generated.
|
||||
*/
|
||||
GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED = (1u << 3),
|
||||
|
||||
/** mark large rewrites for split (`--break-rewrites=/M`) */
|
||||
/** Mark significant rewrites for split (`--break-rewrites=/M`) */
|
||||
GIT_DIFF_FIND_REWRITES = (1u << 4),
|
||||
/** actually split large rewrites into delete/add pairs */
|
||||
/** Actually split large rewrites into delete/add pairs */
|
||||
GIT_DIFF_BREAK_REWRITES = (1u << 5),
|
||||
/** mark rewrites for split and break into delete/add pairs */
|
||||
/** Mark rewrites for split and break into delete/add pairs */
|
||||
GIT_DIFF_FIND_AND_BREAK_REWRITES =
|
||||
(GIT_DIFF_FIND_REWRITES | GIT_DIFF_BREAK_REWRITES),
|
||||
|
||||
/** find renames/copies for untracked items in working directory */
|
||||
/** Find renames/copies for UNTRACKED items in working directory.
|
||||
*
|
||||
* For this to work correctly, use GIT_DIFF_INCLUDE_UNTRACKED when the
|
||||
* initial `git_diff` is being generated (and obviously the diff must
|
||||
* be against the working directory for this to make sense).
|
||||
*/
|
||||
GIT_DIFF_FIND_FOR_UNTRACKED = (1u << 6),
|
||||
|
||||
/** turn on all finding features */
|
||||
/** Turn on all finding features. */
|
||||
GIT_DIFF_FIND_ALL = (0x0ff),
|
||||
|
||||
/** measure similarity ignoring leading whitespace (default) */
|
||||
/** Measure similarity ignoring leading whitespace (default) */
|
||||
GIT_DIFF_FIND_IGNORE_LEADING_WHITESPACE = 0,
|
||||
/** measure similarity ignoring all whitespace */
|
||||
/** Measure similarity ignoring all whitespace */
|
||||
GIT_DIFF_FIND_IGNORE_WHITESPACE = (1u << 12),
|
||||
/** measure similarity including all data */
|
||||
/** Measure similarity including all data */
|
||||
GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE = (1u << 13),
|
||||
/** measure similarity only by comparing SHAs (fast and cheap) */
|
||||
/** Measure similarity only by comparing SHAs (fast and cheap) */
|
||||
GIT_DIFF_FIND_EXACT_MATCH_ONLY = (1u << 14),
|
||||
|
||||
/** do not break rewrites unless they contribute to a rename */
|
||||
/** Do not break rewrites unless they contribute to a rename.
|
||||
*
|
||||
* Normally, GIT_DIFF_FIND_AND_BREAK_REWRITES will measure the self-
|
||||
* similarity of modified files and split the ones that have changed a
|
||||
* lot into a DELETE / ADD pair. Then the sides of that pair will be
|
||||
* considered candidates for rename and copy detection.
|
||||
*
|
||||
* If you add this flag in and the split pair is *not* used for an
|
||||
* actual rename or copy, then the modified record will be restored to
|
||||
* a regular MODIFIED record instead of being split.
|
||||
*/
|
||||
GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY = (1u << 15),
|
||||
|
||||
/** Remove any UNMODIFIED deltas after find_similar is done.
|
||||
*
|
||||
* Using GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED to emulate the
|
||||
* --find-copies-harder behavior requires building a diff with the
|
||||
* GIT_DIFF_INCLUDE_UNMODIFIED flag. If you do not want UNMODIFIED
|
||||
* records in the final result, pass this flag to have them removed.
|
||||
*/
|
||||
GIT_DIFF_FIND_REMOVE_UNMODIFIED = (1u << 16),
|
||||
} git_diff_find_t;
|
||||
|
||||
/**
|
||||
@ -543,7 +599,11 @@ typedef struct {
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
|
||||
/** Combination of git_diff_find_t values (default FIND_RENAMES) */
|
||||
/**
|
||||
* Combination of git_diff_find_t values (default GIT_DIFF_FIND_BY_CONFIG).
|
||||
* NOTE: if you don't explicitly set this, `diff.renames` could be set
|
||||
* to false, resulting in `git_diff_find_similar` doing nothing.
|
||||
*/
|
||||
uint32_t flags;
|
||||
|
||||
/** Similarity to consider a file renamed (default 50) */
|
||||
@ -567,6 +627,18 @@ typedef struct {
|
||||
#define GIT_DIFF_FIND_OPTIONS_VERSION 1
|
||||
#define GIT_DIFF_FIND_OPTIONS_INIT {GIT_DIFF_FIND_OPTIONS_VERSION}
|
||||
|
||||
/**
|
||||
* Initializes a `git_diff_find_options` with default values. Equivalent to
|
||||
* creating an instance with GIT_DIFF_FIND_OPTIONS_INIT.
|
||||
*
|
||||
* @param opts The `git_diff_find_options` struct to initialize
|
||||
* @param version Version of struct; pass `GIT_DIFF_FIND_OPTIONS_VERSION`
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_find_init_options(
|
||||
git_diff_find_options *opts,
|
||||
unsigned int version);
|
||||
|
||||
/** @name Diff Generator Functions
|
||||
*
|
||||
* These are the functions you would use to create (or destroy) a
|
||||
@ -662,24 +734,17 @@ GIT_EXTERN(int) git_diff_index_to_workdir(
|
||||
* The tree you provide will be used for the "old_file" side of the delta,
|
||||
* and the working directory will be used for the "new_file" side.
|
||||
*
|
||||
* Please note: this is *NOT* the same as `git diff <treeish>`. Running
|
||||
* `git diff HEAD` or the like actually uses information from the index,
|
||||
* along with the tree and working directory info.
|
||||
* This is not the same as `git diff <treeish>` or `git diff-index
|
||||
* <treeish>`. Those commands use information from the index, whereas this
|
||||
* function strictly returns the differences between the tree and the files
|
||||
* in the working directory, regardless of the state of the index. Use
|
||||
* `git_diff_tree_to_workdir_with_index` to emulate those commands.
|
||||
*
|
||||
* This function returns strictly the differences between the tree and the
|
||||
* files contained in the working directory, regardless of the state of
|
||||
* files in the index. It may come as a surprise, but there is no direct
|
||||
* equivalent in core git.
|
||||
*
|
||||
* To emulate `git diff <tree>`, use `git_diff_tree_to_workdir_with_index`
|
||||
* (or `git_diff_tree_to_index` and `git_diff_index_to_workdir`, then call
|
||||
* `git_diff_merge` on the results). That will yield a `git_diff` that
|
||||
* matches the git output.
|
||||
*
|
||||
* If this seems confusing, take the case of a file with a staged deletion
|
||||
* where the file has then been put back into the working dir and modified.
|
||||
* The tree-to-workdir diff for that file is 'modified', but core git would
|
||||
* show status 'deleted' since there is a pending deletion in the index.
|
||||
* To see difference between this and `git_diff_tree_to_workdir_with_index`,
|
||||
* consider the example of a staged file deletion where the file has then
|
||||
* been put back into the working dir and further modified. The
|
||||
* tree-to-workdir diff for that file is 'modified', but `git diff` would
|
||||
* show status 'deleted' since there is a staged delete.
|
||||
*
|
||||
* @param diff A pointer to a git_diff pointer that will be allocated.
|
||||
* @param repo The repository containing the tree.
|
||||
@ -744,23 +809,6 @@ GIT_EXTERN(int) git_diff_find_similar(
|
||||
git_diff *diff,
|
||||
const git_diff_find_options *options);
|
||||
|
||||
/**
|
||||
* Initialize diff options structure
|
||||
*
|
||||
* In most cases, you can probably just use `GIT_DIFF_OPTIONS_INIT` to
|
||||
* initialize the diff options structure, but in some cases that is not
|
||||
* going to work. You can call this function instead. Note that you
|
||||
* must pass both a pointer to the structure to be initialized and the
|
||||
* `GIT_DIFF_OPTIONS_VERSION` value from the header you compiled with.
|
||||
*
|
||||
* @param options Pointer to git_diff_options memory to be initialized
|
||||
* @param version Should be `GIT_DIFF_OPTIONS_VERSION`
|
||||
* @return 0 on success, negative on failure (such as unsupported version)
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_options_init(
|
||||
git_diff_options *options,
|
||||
unsigned int version);
|
||||
|
||||
/**@}*/
|
||||
|
||||
|
||||
@ -833,7 +881,7 @@ GIT_EXTERN(int) git_diff_is_sorted_icase(const git_diff *diff);
|
||||
* files whose only changed is a file mode change.
|
||||
*
|
||||
* Returning a non-zero value from any of the callbacks will terminate
|
||||
* the iteration and cause this return `GIT_EUSER`.
|
||||
* the iteration and return the value to the user.
|
||||
*
|
||||
* @param diff A git_diff generated by one of the above functions.
|
||||
* @param file_cb Callback function to make per file in the diff.
|
||||
@ -844,7 +892,7 @@ GIT_EXTERN(int) git_diff_is_sorted_icase(const git_diff *diff);
|
||||
* same callback will be made for context lines, added, and
|
||||
* removed lines, and even for a deleted trailing newline.
|
||||
* @param payload Reference pointer that will be passed to your callbacks.
|
||||
* @return 0 on success, GIT_EUSER on non-zero callback, or error code
|
||||
* @return 0 on success, non-zero callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_foreach(
|
||||
git_diff *diff,
|
||||
@ -881,13 +929,13 @@ typedef enum {
|
||||
* Iterate over a diff generating formatted text output.
|
||||
*
|
||||
* Returning a non-zero value from the callbacks will terminate the
|
||||
* iteration and cause this return `GIT_EUSER`.
|
||||
* iteration and return the non-zero value to the caller.
|
||||
*
|
||||
* @param diff A git_diff generated by one of the above functions.
|
||||
* @param format A git_diff_format_t value to pick the text format.
|
||||
* @param print_cb Callback to make per line of diff text.
|
||||
* @param payload Reference pointer that will be passed to your callback.
|
||||
* @return 0 on success, GIT_EUSER on non-zero callback, or error code
|
||||
* @return 0 on success, non-zero callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_print(
|
||||
git_diff *diff,
|
||||
@ -927,7 +975,7 @@ GIT_EXTERN(int) git_diff_print(
|
||||
* @param hunk_cb Callback for each hunk in diff; can be NULL
|
||||
* @param line_cb Callback for each line in diff; can be NULL
|
||||
* @param payload Payload passed to each callback function
|
||||
* @return 0 on success, GIT_EUSER on non-zero callback return, or error code
|
||||
* @return 0 on success, non-zero callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_blobs(
|
||||
const git_blob *old_blob,
|
||||
@ -962,7 +1010,7 @@ GIT_EXTERN(int) git_diff_blobs(
|
||||
* @param hunk_cb Callback for each hunk in diff; can be NULL
|
||||
* @param line_cb Callback for each line in diff; can be NULL
|
||||
* @param payload Payload passed to each callback function
|
||||
* @return 0 on success, GIT_EUSER on non-zero callback return, or error code
|
||||
* @return 0 on success, non-zero callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_blob_to_buffer(
|
||||
const git_blob *old_blob,
|
||||
@ -976,6 +1024,214 @@ GIT_EXTERN(int) git_diff_blob_to_buffer(
|
||||
git_diff_line_cb line_cb,
|
||||
void *payload);
|
||||
|
||||
/**
|
||||
* Directly run a diff between two buffers.
|
||||
*
|
||||
* Even more than with `git_diff_blobs`, comparing two buffer lacks
|
||||
* context, so the `git_diff_file` parameters to the callbacks will be
|
||||
* faked a la the rules for `git_diff_blobs()`.
|
||||
*
|
||||
* @param old_buffer Raw data for old side of diff, or NULL for empty
|
||||
* @param old_len Length of the raw data for old side of the diff
|
||||
* @param old_as_path Treat old buffer as if it had this filename; can be NULL
|
||||
* @param new_buffer Raw data for new side of diff, or NULL for empty
|
||||
* @param new_len Length of raw data for new side of diff
|
||||
* @param new_as_path Treat buffer as if it had this filename; can be NULL
|
||||
* @param options Options for diff, or NULL for default options
|
||||
* @param file_cb Callback for "file"; made once if there is a diff; can be NULL
|
||||
* @param hunk_cb Callback for each hunk in diff; can be NULL
|
||||
* @param line_cb Callback for each line in diff; can be NULL
|
||||
* @param payload Payload passed to each callback function
|
||||
* @return 0 on success, non-zero callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_buffers(
|
||||
const void *old_buffer,
|
||||
size_t old_len,
|
||||
const char *old_as_path,
|
||||
const void *new_buffer,
|
||||
size_t new_len,
|
||||
const char *new_as_path,
|
||||
const git_diff_options *options,
|
||||
git_diff_file_cb file_cb,
|
||||
git_diff_hunk_cb hunk_cb,
|
||||
git_diff_line_cb line_cb,
|
||||
void *payload);
|
||||
|
||||
/**
|
||||
* This is an opaque structure which is allocated by `git_diff_get_stats`.
|
||||
* You are responsible for releasing the object memory when done, using the
|
||||
* `git_diff_stats_free()` function.
|
||||
*/
|
||||
typedef struct git_diff_stats git_diff_stats;
|
||||
|
||||
/**
|
||||
* Formatting options for diff stats
|
||||
*/
|
||||
typedef enum {
|
||||
/** No stats*/
|
||||
GIT_DIFF_STATS_NONE = 0,
|
||||
|
||||
/** Full statistics, equivalent of `--stat` */
|
||||
GIT_DIFF_STATS_FULL = (1u << 0),
|
||||
|
||||
/** Short statistics, equivalent of `--shortstat` */
|
||||
GIT_DIFF_STATS_SHORT = (1u << 1),
|
||||
|
||||
/** Number statistics, equivalent of `--numstat` */
|
||||
GIT_DIFF_STATS_NUMBER = (1u << 2),
|
||||
|
||||
/** Extended header information such as creations, renames and mode changes, equivalent of `--summary` */
|
||||
GIT_DIFF_STATS_INCLUDE_SUMMARY = (1u << 3),
|
||||
} git_diff_stats_format_t;
|
||||
|
||||
/**
|
||||
* Accumlate diff statistics for all patches.
|
||||
*
|
||||
* @param out Structure containg the diff statistics.
|
||||
* @param diff A git_diff generated by one of the above functions.
|
||||
* @return 0 on success; non-zero on error
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_get_stats(
|
||||
git_diff_stats **out,
|
||||
git_diff *diff);
|
||||
|
||||
/**
|
||||
* Get the total number of files changed in a diff
|
||||
*
|
||||
* @param stats A `git_diff_stats` generated by one of the above functions.
|
||||
* @return total number of files changed in the diff
|
||||
*/
|
||||
GIT_EXTERN(size_t) git_diff_stats_files_changed(
|
||||
const git_diff_stats *stats);
|
||||
|
||||
/**
|
||||
* Get the total number of insertions in a diff
|
||||
*
|
||||
* @param stats A `git_diff_stats` generated by one of the above functions.
|
||||
* @return total number of insertions in the diff
|
||||
*/
|
||||
GIT_EXTERN(size_t) git_diff_stats_insertions(
|
||||
const git_diff_stats *stats);
|
||||
|
||||
/**
|
||||
* Get the total number of deletions in a diff
|
||||
*
|
||||
* @param stats A `git_diff_stats` generated by one of the above functions.
|
||||
* @return total number of deletions in the diff
|
||||
*/
|
||||
GIT_EXTERN(size_t) git_diff_stats_deletions(
|
||||
const git_diff_stats *stats);
|
||||
|
||||
/**
|
||||
* Print diff statistics to a `git_buf`.
|
||||
*
|
||||
* @param out buffer to store the formatted diff statistics in.
|
||||
* @param stats A `git_diff_stats` generated by one of the above functions.
|
||||
* @param format Formatting option.
|
||||
* @param width Target width for output (only affects GIT_DIFF_STATS_FULL)
|
||||
* @return 0 on success; non-zero on error
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_stats_to_buf(
|
||||
git_buf *out,
|
||||
const git_diff_stats *stats,
|
||||
git_diff_stats_format_t format,
|
||||
size_t width);
|
||||
|
||||
/**
|
||||
* Deallocate a `git_diff_stats`.
|
||||
*
|
||||
* @param stats The previously created statistics object;
|
||||
* cannot be used after free.
|
||||
*/
|
||||
GIT_EXTERN(void) git_diff_stats_free(git_diff_stats *stats);
|
||||
|
||||
/**
|
||||
* Formatting options for diff e-mail generation
|
||||
*/
|
||||
typedef enum {
|
||||
/** Normal patch, the default */
|
||||
GIT_DIFF_FORMAT_EMAIL_NONE = 0,
|
||||
|
||||
/** Don't insert "[PATCH]" in the subject header*/
|
||||
GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER = (1 << 0),
|
||||
|
||||
} git_diff_format_email_flags_t;
|
||||
|
||||
/**
|
||||
* Options for controlling the formatting of the generated e-mail.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
|
||||
git_diff_format_email_flags_t flags;
|
||||
|
||||
/** This patch number */
|
||||
size_t patch_no;
|
||||
|
||||
/** Total number of patches in this series */
|
||||
size_t total_patches;
|
||||
|
||||
/** id to use for the commit */
|
||||
const git_oid *id;
|
||||
|
||||
/** Summary of the change */
|
||||
const char *summary;
|
||||
|
||||
/** Author of the change */
|
||||
const git_signature *author;
|
||||
} git_diff_format_email_options;
|
||||
|
||||
#define GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION 1
|
||||
#define GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT {GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION, 0, 1, 1, NULL, NULL, NULL}
|
||||
|
||||
/**
|
||||
* Create an e-mail ready patch from a diff.
|
||||
*
|
||||
* @param out buffer to store the e-mail patch in
|
||||
* @param diff containing the commit
|
||||
* @param opts structure with options to influence content and formatting.
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_format_email(
|
||||
git_buf *out,
|
||||
git_diff *diff,
|
||||
const git_diff_format_email_options *opts);
|
||||
|
||||
/**
|
||||
* Create an e-mail ready patch for a commit.
|
||||
*
|
||||
* Does not support creating patches for merge commits (yet).
|
||||
*
|
||||
* @param out buffer to store the e-mail patch in
|
||||
* @param repo containing the commit
|
||||
* @param commit pointer to up commit
|
||||
* @param patch_no patch number of the commit
|
||||
* @param total_patches total number of patches in the patch set
|
||||
* @param flags determines the formatting of the e-mail
|
||||
* @param diff_opts structure with options to influence diff or NULL for defaults.
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_commit_as_email(
|
||||
git_buf *out,
|
||||
git_repository *repo,
|
||||
git_commit *commit,
|
||||
size_t patch_no,
|
||||
size_t total_patches,
|
||||
git_diff_format_email_flags_t flags,
|
||||
const git_diff_options *diff_opts);
|
||||
|
||||
/**
|
||||
* Initializes a `git_diff_format_email_options` with default values.
|
||||
*
|
||||
* Equivalent to creating an instance with GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT.
|
||||
*
|
||||
* @param opts The `git_diff_format_email_options` struct to initialize
|
||||
* @param version Version of struct; pass `GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION`
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_format_email_init_options(
|
||||
git_diff_format_email_options *opts,
|
||||
unsigned int version);
|
||||
|
||||
GIT_END_DECL
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
#define INCLUDE_git_errors_h__
|
||||
|
||||
#include "common.h"
|
||||
#include "buffer.h"
|
||||
|
||||
/**
|
||||
* @file git2/errors.h
|
||||
@ -20,25 +19,39 @@ GIT_BEGIN_DECL
|
||||
|
||||
/** Generic return codes */
|
||||
typedef enum {
|
||||
GIT_OK = 0,
|
||||
GIT_ERROR = -1,
|
||||
GIT_ENOTFOUND = -3,
|
||||
GIT_EEXISTS = -4,
|
||||
GIT_EAMBIGUOUS = -5,
|
||||
GIT_EBUFS = -6,
|
||||
GIT_EUSER = -7,
|
||||
GIT_EBAREREPO = -8,
|
||||
GIT_EUNBORNBRANCH = -9,
|
||||
GIT_EUNMERGED = -10,
|
||||
GIT_ENONFASTFORWARD = -11,
|
||||
GIT_EINVALIDSPEC = -12,
|
||||
GIT_EMERGECONFLICT = -13,
|
||||
GIT_ELOCKED = -14,
|
||||
GIT_OK = 0, /**< No error */
|
||||
|
||||
GIT_PASSTHROUGH = -30,
|
||||
GIT_ITEROVER = -31,
|
||||
GIT_ERROR = -1, /**< Generic error */
|
||||
GIT_ENOTFOUND = -3, /**< Requested object could not be found */
|
||||
GIT_EEXISTS = -4, /**< Object exists preventing operation */
|
||||
GIT_EAMBIGUOUS = -5, /**< More than one object matches */
|
||||
GIT_EBUFS = -6, /**< Output buffer too short to hold data */
|
||||
|
||||
/* GIT_EUSER is a special error that is never generated by libgit2
|
||||
* code. You can return it from a callback (e.g to stop an iteration)
|
||||
* to know that it was generated by the callback and not by libgit2.
|
||||
*/
|
||||
GIT_EUSER = -7,
|
||||
|
||||
GIT_EBAREREPO = -8, /**< Operation not allowed on bare repository */
|
||||
GIT_EUNBORNBRANCH = -9, /**< HEAD refers to branch with no commits */
|
||||
GIT_EUNMERGED = -10, /**< Merge in progress prevented operation */
|
||||
GIT_ENONFASTFORWARD = -11, /**< Reference was not fast-forwardable */
|
||||
GIT_EINVALIDSPEC = -12, /**< Name/ref spec was not in a valid format */
|
||||
GIT_EMERGECONFLICT = -13, /**< Merge conflicts prevented operation */
|
||||
GIT_ELOCKED = -14, /**< Lock file prevented operation */
|
||||
GIT_EMODIFIED = -15, /**< Reference value does not match expected */
|
||||
|
||||
GIT_PASSTHROUGH = -30, /**< Internal only */
|
||||
GIT_ITEROVER = -31, /**< Signals end of iteration with iterator */
|
||||
} git_error_code;
|
||||
|
||||
/**
|
||||
* Structure to store extra details of the last error that occurred.
|
||||
*
|
||||
* This is kept on a per-thread basis if GIT_THREADS was defined when the
|
||||
* library was build, otherwise one is kept globally for the library
|
||||
*/
|
||||
typedef struct {
|
||||
char *message;
|
||||
int klass;
|
||||
@ -71,6 +84,9 @@ typedef enum {
|
||||
GITERR_MERGE,
|
||||
GITERR_SSH,
|
||||
GITERR_FILTER,
|
||||
GITERR_REVERT,
|
||||
GITERR_CALLBACK,
|
||||
GITERR_CHERRYPICK,
|
||||
} git_error_t;
|
||||
|
||||
/**
|
||||
@ -90,7 +106,7 @@ GIT_EXTERN(void) giterr_clear(void);
|
||||
* Get the last error data and clear it.
|
||||
*
|
||||
* This copies the last error into the given `git_error` struct
|
||||
* and returns 0 if the copy was successful, leaving the error
|
||||
* and returns 0 if the copy was successful, leaving the error
|
||||
* cleared as if `giterr_clear` had been called.
|
||||
*
|
||||
* If there was no existing error in the library, -1 will be returned
|
||||
|
@ -35,6 +35,11 @@ typedef enum {
|
||||
GIT_FILTER_CLEAN = GIT_FILTER_TO_ODB,
|
||||
} git_filter_mode_t;
|
||||
|
||||
typedef enum {
|
||||
GIT_FILTER_OPT_DEFAULT = 0u,
|
||||
GIT_FILTER_OPT_ALLOW_UNSAFE = (1u << 0),
|
||||
} git_filter_opt_t;
|
||||
|
||||
/**
|
||||
* A filter that can transform file data
|
||||
*
|
||||
@ -75,6 +80,7 @@ typedef struct git_filter_list git_filter_list;
|
||||
* @param blob The blob to which the filter will be applied (if known)
|
||||
* @param path Relative path of the file to be filtered
|
||||
* @param mode Filtering direction (WT->ODB or ODB->WT)
|
||||
* @param options Combination of `git_filter_opt_t` flags
|
||||
* @return 0 on success (which could still return NULL if no filters are
|
||||
* needed for the requested file), <0 on error
|
||||
*/
|
||||
@ -83,7 +89,8 @@ GIT_EXTERN(int) git_filter_list_load(
|
||||
git_repository *repo,
|
||||
git_blob *blob, /* can be NULL */
|
||||
const char *path,
|
||||
git_filter_mode_t mode);
|
||||
git_filter_mode_t mode,
|
||||
uint32_t options);
|
||||
|
||||
/**
|
||||
* Apply filter list to a data buffer.
|
||||
|
@ -36,6 +36,20 @@ GIT_BEGIN_DECL
|
||||
*/
|
||||
GIT_EXTERN(int) git_graph_ahead_behind(size_t *ahead, size_t *behind, git_repository *repo, const git_oid *local, const git_oid *upstream);
|
||||
|
||||
|
||||
/**
|
||||
* Determine if a commit is the descendant of another commit.
|
||||
*
|
||||
* @param commit a previously loaded commit.
|
||||
* @param ancestor a potential ancestor commit.
|
||||
* @return 1 if the given commit is a descendant of the potential ancestor,
|
||||
* 0 if not, error code otherwise.
|
||||
*/
|
||||
GIT_EXTERN(int) git_graph_descendant_of(
|
||||
git_repository *repo,
|
||||
const git_oid *commit,
|
||||
const git_oid *ancestor);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
#endif
|
||||
|
@ -56,12 +56,12 @@ typedef struct git_index_entry {
|
||||
unsigned int gid;
|
||||
git_off_t file_size;
|
||||
|
||||
git_oid oid;
|
||||
git_oid id;
|
||||
|
||||
unsigned short flags;
|
||||
unsigned short flags_extended;
|
||||
|
||||
char *path;
|
||||
const char *path;
|
||||
} git_index_entry;
|
||||
|
||||
/**
|
||||
@ -73,11 +73,19 @@ typedef struct git_index_entry {
|
||||
*/
|
||||
#define GIT_IDXENTRY_NAMEMASK (0x0fff)
|
||||
#define GIT_IDXENTRY_STAGEMASK (0x3000)
|
||||
#define GIT_IDXENTRY_EXTENDED (0x4000)
|
||||
#define GIT_IDXENTRY_VALID (0x8000)
|
||||
#define GIT_IDXENTRY_STAGESHIFT 12
|
||||
|
||||
#define GIT_IDXENTRY_STAGE(E) (((E)->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT)
|
||||
typedef enum {
|
||||
GIT_IDXENTRY_EXTENDED = (0x4000),
|
||||
GIT_IDXENTRY_VALID = (0x8000),
|
||||
} git_indxentry_flag_t;
|
||||
|
||||
#define GIT_IDXENTRY_STAGE(E) \
|
||||
(((E)->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT)
|
||||
|
||||
#define GIT_IDXENTRY_STAGE_SET(E,S) do { \
|
||||
(E)->flags = ((E)->flags & ~GIT_IDXENTRY_STAGEMASK) | \
|
||||
(((S) & 0x03) << GIT_IDXENTRY_STAGESHIFT); } while (0)
|
||||
|
||||
/**
|
||||
* Bitmasks for on-disk fields of `git_index_entry`'s `flags_extended`
|
||||
@ -87,43 +95,43 @@ typedef struct git_index_entry {
|
||||
* in-memory only and used by libgit2. Only the flags in
|
||||
* `GIT_IDXENTRY_EXTENDED_FLAGS` will get saved on-disk.
|
||||
*
|
||||
* These bitmasks match the three fields in the `git_index_entry`
|
||||
* `flags_extended` value that belong on disk. You can use them to
|
||||
* interpret the data in the `flags_extended`.
|
||||
*/
|
||||
#define GIT_IDXENTRY_INTENT_TO_ADD (1 << 13)
|
||||
#define GIT_IDXENTRY_SKIP_WORKTREE (1 << 14)
|
||||
/* GIT_IDXENTRY_EXTENDED2 is reserved for future extension */
|
||||
#define GIT_IDXENTRY_EXTENDED2 (1 << 15)
|
||||
|
||||
#define GIT_IDXENTRY_EXTENDED_FLAGS (GIT_IDXENTRY_INTENT_TO_ADD | GIT_IDXENTRY_SKIP_WORKTREE)
|
||||
|
||||
/**
|
||||
* Bitmasks for in-memory only fields of `git_index_entry`'s `flags_extended`
|
||||
*
|
||||
* These bitmasks match the other fields in the `git_index_entry`
|
||||
* `flags_extended` value that are only used in-memory by libgit2. You
|
||||
* Thee first three bitmasks match the three fields in the
|
||||
* `git_index_entry` `flags_extended` value that belong on disk. You
|
||||
* can use them to interpret the data in the `flags_extended`.
|
||||
*
|
||||
* The rest of the bitmasks match the other fields in the `git_index_entry`
|
||||
* `flags_extended` value that are only used in-memory by libgit2.
|
||||
* You can use them to interpret the data in the `flags_extended`.
|
||||
*
|
||||
*/
|
||||
#define GIT_IDXENTRY_UPDATE (1 << 0)
|
||||
#define GIT_IDXENTRY_REMOVE (1 << 1)
|
||||
#define GIT_IDXENTRY_UPTODATE (1 << 2)
|
||||
#define GIT_IDXENTRY_ADDED (1 << 3)
|
||||
typedef enum {
|
||||
|
||||
#define GIT_IDXENTRY_HASHED (1 << 4)
|
||||
#define GIT_IDXENTRY_UNHASHED (1 << 5)
|
||||
#define GIT_IDXENTRY_WT_REMOVE (1 << 6) /* remove in work directory */
|
||||
#define GIT_IDXENTRY_CONFLICTED (1 << 7)
|
||||
GIT_IDXENTRY_INTENT_TO_ADD = (1 << 13),
|
||||
GIT_IDXENTRY_SKIP_WORKTREE = (1 << 14),
|
||||
/** Reserved for future extension */
|
||||
GIT_IDXENTRY_EXTENDED2 = (1 << 15),
|
||||
|
||||
#define GIT_IDXENTRY_UNPACKED (1 << 8)
|
||||
#define GIT_IDXENTRY_NEW_SKIP_WORKTREE (1 << 9)
|
||||
GIT_IDXENTRY_EXTENDED_FLAGS = (GIT_IDXENTRY_INTENT_TO_ADD | GIT_IDXENTRY_SKIP_WORKTREE),
|
||||
GIT_IDXENTRY_UPDATE = (1 << 0),
|
||||
GIT_IDXENTRY_REMOVE = (1 << 1),
|
||||
GIT_IDXENTRY_UPTODATE = (1 << 2),
|
||||
GIT_IDXENTRY_ADDED = (1 << 3),
|
||||
|
||||
GIT_IDXENTRY_HASHED = (1 << 4),
|
||||
GIT_IDXENTRY_UNHASHED = (1 << 5),
|
||||
GIT_IDXENTRY_WT_REMOVE = (1 << 6), /**< remove in work directory */
|
||||
GIT_IDXENTRY_CONFLICTED = (1 << 7),
|
||||
|
||||
GIT_IDXENTRY_UNPACKED = (1 << 8),
|
||||
GIT_IDXENTRY_NEW_SKIP_WORKTREE = (1 << 9),
|
||||
} git_idxentry_extended_flag_t;
|
||||
|
||||
/** Capabilities of system that affect index actions. */
|
||||
typedef enum {
|
||||
GIT_INDEXCAP_IGNORE_CASE = 1u,
|
||||
GIT_INDEXCAP_NO_FILEMODE = 2u,
|
||||
GIT_INDEXCAP_NO_SYMLINKS = 4u,
|
||||
GIT_INDEXCAP_FROM_OWNER = ~0u
|
||||
GIT_INDEXCAP_IGNORE_CASE = 1,
|
||||
GIT_INDEXCAP_NO_FILEMODE = 2,
|
||||
GIT_INDEXCAP_NO_SYMLINKS = 4,
|
||||
GIT_INDEXCAP_FROM_OWNER = -1,
|
||||
} git_indexcap_t;
|
||||
|
||||
/** Callback for APIs that add/remove/update files matching pathspec */
|
||||
@ -158,8 +166,8 @@ typedef enum {
|
||||
* to back it.
|
||||
*
|
||||
* Since there is no ODB or working directory behind this index,
|
||||
* any Index methods which rely on these (e.g. index_add) will
|
||||
* fail with the GIT_EBAREINDEX error code.
|
||||
* any Index methods which rely on these (e.g. index_add_bypath)
|
||||
* will fail with the GIT_ERROR error code.
|
||||
*
|
||||
* If you need to access the index of an actual repository,
|
||||
* use the `git_repository_index` wrapper.
|
||||
@ -206,7 +214,7 @@ GIT_EXTERN(git_repository *) git_index_owner(const git_index *index);
|
||||
* @param index An existing index object
|
||||
* @return A combination of GIT_INDEXCAP values
|
||||
*/
|
||||
GIT_EXTERN(unsigned int) git_index_caps(const git_index *index);
|
||||
GIT_EXTERN(int) git_index_caps(const git_index *index);
|
||||
|
||||
/**
|
||||
* Set index capabilities flags.
|
||||
@ -219,7 +227,7 @@ GIT_EXTERN(unsigned int) git_index_caps(const git_index *index);
|
||||
* @param caps A combination of GIT_INDEXCAP values
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
GIT_EXTERN(int) git_index_set_caps(git_index *index, unsigned int caps);
|
||||
GIT_EXTERN(int) git_index_set_caps(git_index *index, int caps);
|
||||
|
||||
/**
|
||||
* Update the contents of an existing index object in memory by reading
|
||||
@ -255,7 +263,7 @@ GIT_EXTERN(int) git_index_write(git_index *index);
|
||||
* @param index an existing index object
|
||||
* @return path to index file or NULL for in-memory index
|
||||
*/
|
||||
GIT_EXTERN(const char *) git_index_path(git_index *index);
|
||||
GIT_EXTERN(const char *) git_index_path(const git_index *index);
|
||||
|
||||
/**
|
||||
* Read a tree into the index file with stats
|
||||
@ -327,12 +335,14 @@ GIT_EXTERN(size_t) git_index_entrycount(const git_index *index);
|
||||
|
||||
/**
|
||||
* Clear the contents (all the entries) of an index object.
|
||||
* This clears the index object in memory; changes must be manually
|
||||
* written to disk for them to take effect.
|
||||
*
|
||||
* This clears the index object in memory; changes must be explicitly
|
||||
* written to disk for them to take effect persistently.
|
||||
*
|
||||
* @param index an existing index object
|
||||
* @return 0 on success, error code < 0 on failure
|
||||
*/
|
||||
GIT_EXTERN(void) git_index_clear(git_index *index);
|
||||
GIT_EXTERN(int) git_index_clear(git_index *index);
|
||||
|
||||
/**
|
||||
* Get a pointer to one of the entries in the index
|
||||
@ -405,10 +415,10 @@ GIT_EXTERN(int) git_index_add(git_index *index, const git_index_entry *source_en
|
||||
*
|
||||
* This entry is calculated from the entry's flag attribute like this:
|
||||
*
|
||||
* (entry->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT
|
||||
* (entry->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT
|
||||
*
|
||||
* @param entry The entry
|
||||
* @returns the stage number
|
||||
* @return the stage number
|
||||
*/
|
||||
GIT_EXTERN(int) git_index_entry_stage(const git_index_entry *entry);
|
||||
|
||||
@ -493,7 +503,7 @@ GIT_EXTERN(int) git_index_remove_bypath(git_index *index, const char *path);
|
||||
* item in the working directory immediately *before* it is added to /
|
||||
* updated in the index. Returning zero will add the item to the index,
|
||||
* greater than zero will skip the item, and less than zero will abort the
|
||||
* scan and cause GIT_EUSER to be returned.
|
||||
* scan and return that value to the caller.
|
||||
*
|
||||
* @param index an existing index object
|
||||
* @param pathspec array of path patterns
|
||||
@ -502,7 +512,7 @@ GIT_EXTERN(int) git_index_remove_bypath(git_index *index, const char *path);
|
||||
* gets index of matching pathspec entry); can be NULL;
|
||||
* return 0 to add, >0 to skip, <0 to abort scan.
|
||||
* @param payload payload passed through to callback function
|
||||
* @return 0 or an error code
|
||||
* @return 0 on success, negative callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_index_add_all(
|
||||
git_index *index,
|
||||
@ -524,7 +534,7 @@ GIT_EXTERN(int) git_index_add_all(
|
||||
* gets index of matching pathspec entry); can be NULL;
|
||||
* return 0 to add, >0 to skip, <0 to abort scan.
|
||||
* @param payload payload passed through to callback function
|
||||
* @return 0 or an error code
|
||||
* @return 0 on success, negative callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_index_remove_all(
|
||||
git_index *index,
|
||||
@ -553,7 +563,7 @@ GIT_EXTERN(int) git_index_remove_all(
|
||||
* gets index of matching pathspec entry); can be NULL;
|
||||
* return 0 to add, >0 to skip, <0 to abort scan.
|
||||
* @param payload payload passed through to callback function
|
||||
* @return 0 or an error code
|
||||
* @return 0 on success, negative callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_index_update_all(
|
||||
git_index *index,
|
||||
@ -568,8 +578,7 @@ GIT_EXTERN(int) git_index_update_all(
|
||||
* @param at_pos the address to which the position of the index entry is written (optional)
|
||||
* @param index an existing index object
|
||||
* @param path path to search
|
||||
* @return a zero-based position in the index if found;
|
||||
* GIT_ENOTFOUND otherwise
|
||||
* @return a zero-based position in the index if found; GIT_ENOTFOUND otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_index_find(size_t *at_pos, git_index *index, const char *path);
|
||||
|
||||
@ -613,6 +622,7 @@ GIT_EXTERN(int) git_index_conflict_add(
|
||||
* @param their_out Pointer to store the their entry
|
||||
* @param index an existing index object
|
||||
* @param path path to search
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_index_conflict_get(
|
||||
const git_index_entry **ancestor_out,
|
||||
@ -625,16 +635,18 @@ GIT_EXTERN(int) git_index_conflict_get(
|
||||
* Removes the index entries that represent a conflict of a single file.
|
||||
*
|
||||
* @param index an existing index object
|
||||
* @param path to search
|
||||
* @param path path to remove conflicts for
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_index_conflict_remove(git_index *index, const char *path);
|
||||
|
||||
/**
|
||||
* Remove all conflicts in the index (entries with a stage greater than 0.)
|
||||
* Remove all conflicts in the index (entries with a stage greater than 0).
|
||||
*
|
||||
* @param index an existing index object
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(void) git_index_conflict_cleanup(git_index *index);
|
||||
GIT_EXTERN(int) git_index_conflict_cleanup(git_index *index);
|
||||
|
||||
/**
|
||||
* Determine if the index contains entries representing file conflicts.
|
||||
@ -644,9 +656,12 @@ GIT_EXTERN(void) git_index_conflict_cleanup(git_index *index);
|
||||
GIT_EXTERN(int) git_index_has_conflicts(const git_index *index);
|
||||
|
||||
/**
|
||||
* Create an iterator for the conflicts in the index. You may not modify the
|
||||
* index while iterating, the results are undefined.
|
||||
* Create an iterator for the conflicts in the index.
|
||||
*
|
||||
* The index must not be modified while iterating; the results are undefined.
|
||||
*
|
||||
* @param iterator_out The newly created conflict iterator
|
||||
* @param index The index to scan
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_index_conflict_iterator_new(
|
||||
|
@ -32,7 +32,7 @@ GIT_EXTERN(int) git_indexer_new(
|
||||
const char *path,
|
||||
unsigned int mode,
|
||||
git_odb *odb,
|
||||
git_transfer_progress_callback progress_cb,
|
||||
git_transfer_progress_cb progress_cb,
|
||||
void *progress_cb_payload);
|
||||
|
||||
/**
|
||||
|
@ -22,71 +22,288 @@
|
||||
*/
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* The file inputs to `git_merge_file`. Callers should populate the
|
||||
* `git_merge_file_input` structure with descriptions of the files in
|
||||
* each side of the conflict for use in producing the merge file.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
|
||||
/** Pointer to the contents of the file. */
|
||||
const char *ptr;
|
||||
|
||||
/** Size of the contents pointed to in `ptr`. */
|
||||
size_t size;
|
||||
|
||||
/** File name of the conflicted file, or `NULL` to not merge the path. */
|
||||
const char *path;
|
||||
|
||||
/** File mode of the conflicted file, or `0` to not merge the mode. */
|
||||
unsigned int mode;
|
||||
} git_merge_file_input;
|
||||
|
||||
#define GIT_MERGE_FILE_INPUT_VERSION 1
|
||||
#define GIT_MERGE_FILE_INPUT_INIT {GIT_MERGE_FILE_INPUT_VERSION}
|
||||
|
||||
/**
|
||||
* Initializes a `git_merge_file_input` with default values. Equivalent to
|
||||
* creating an instance with GIT_MERGE_FILE_INPUT_INIT.
|
||||
*
|
||||
* @param opts the `git_merge_file_input` instance to initialize.
|
||||
* @param version the version of the struct; you should pass
|
||||
* `GIT_MERGE_FILE_INPUT_VERSION` here.
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_file_init_input(
|
||||
git_merge_file_input *opts,
|
||||
unsigned int version);
|
||||
|
||||
/**
|
||||
* Flags for `git_merge_tree` options. A combination of these flags can be
|
||||
* passed in via the `flags` value in the `git_merge_tree_opts`.
|
||||
* passed in via the `flags` value in the `git_merge_options`.
|
||||
*/
|
||||
typedef enum {
|
||||
/** Detect renames */
|
||||
/**
|
||||
* Detect renames that occur between the common ancestor and the "ours"
|
||||
* side or the common ancestor and the "theirs" side. This will enable
|
||||
* the ability to merge between a modified and renamed file.
|
||||
*/
|
||||
GIT_MERGE_TREE_FIND_RENAMES = (1 << 0),
|
||||
} git_merge_tree_flag_t;
|
||||
|
||||
/**
|
||||
* Automerge options for `git_merge_trees_opts`.
|
||||
* Merge file favor options for `git_merge_options` instruct the file-level
|
||||
* merging functionality how to deal with conflicting regions of the files.
|
||||
*/
|
||||
typedef enum {
|
||||
GIT_MERGE_AUTOMERGE_NORMAL = 0,
|
||||
GIT_MERGE_AUTOMERGE_NONE = 1,
|
||||
GIT_MERGE_AUTOMERGE_FAVOR_OURS = 2,
|
||||
GIT_MERGE_AUTOMERGE_FAVOR_THEIRS = 3,
|
||||
} git_merge_automerge_flags;
|
||||
/**
|
||||
* When a region of a file is changed in both branches, a conflict
|
||||
* will be recorded in the index so that `git_checkout` can produce
|
||||
* a merge file with conflict markers in the working directory.
|
||||
* This is the default.
|
||||
*/
|
||||
GIT_MERGE_FILE_FAVOR_NORMAL = 0,
|
||||
|
||||
/**
|
||||
* When a region of a file is changed in both branches, the file
|
||||
* created in the index will contain the "ours" side of any conflicting
|
||||
* region. The index will not record a conflict.
|
||||
*/
|
||||
GIT_MERGE_FILE_FAVOR_OURS = 1,
|
||||
|
||||
/**
|
||||
* When a region of a file is changed in both branches, the file
|
||||
* created in the index will contain the "theirs" side of any conflicting
|
||||
* region. The index will not record a conflict.
|
||||
*/
|
||||
GIT_MERGE_FILE_FAVOR_THEIRS = 2,
|
||||
|
||||
/**
|
||||
* When a region of a file is changed in both branches, the file
|
||||
* created in the index will contain each unique line from each side,
|
||||
* which has the result of combining both files. The index will not
|
||||
* record a conflict.
|
||||
*/
|
||||
GIT_MERGE_FILE_FAVOR_UNION = 3,
|
||||
} git_merge_file_favor_t;
|
||||
|
||||
typedef enum {
|
||||
/* Defaults */
|
||||
GIT_MERGE_FILE_DEFAULT = 0,
|
||||
|
||||
/* Create standard conflicted merge files */
|
||||
GIT_MERGE_FILE_STYLE_MERGE = (1 << 0),
|
||||
|
||||
/* Create diff3-style files */
|
||||
GIT_MERGE_FILE_STYLE_DIFF3 = (1 << 1),
|
||||
|
||||
/* Condense non-alphanumeric regions for simplified diff file */
|
||||
GIT_MERGE_FILE_SIMPLIFY_ALNUM = (1 << 2),
|
||||
} git_merge_file_flags_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
|
||||
/**
|
||||
* Label for the ancestor file side of the conflict which will be prepended
|
||||
* to labels in diff3-format merge files.
|
||||
*/
|
||||
const char *ancestor_label;
|
||||
|
||||
/**
|
||||
* Label for our file side of the conflict which will be prepended
|
||||
* to labels in merge files.
|
||||
*/
|
||||
const char *our_label;
|
||||
|
||||
/**
|
||||
* Label for their file side of the conflict which will be prepended
|
||||
* to labels in merge files.
|
||||
*/
|
||||
const char *their_label;
|
||||
|
||||
/** The file to favor in region conflicts. */
|
||||
git_merge_file_favor_t favor;
|
||||
|
||||
/** Merge file flags. */
|
||||
git_merge_file_flags_t flags;
|
||||
} git_merge_file_options;
|
||||
|
||||
#define GIT_MERGE_FILE_OPTIONS_VERSION 1
|
||||
#define GIT_MERGE_FILE_OPTIONS_INIT {GIT_MERGE_FILE_OPTIONS_VERSION}
|
||||
|
||||
/**
|
||||
* Initializes a `git_merge_file_options` with default values. Equivalent to
|
||||
* creating an instance with GIT_MERGE_FILE_OPTIONS_INIT.
|
||||
*
|
||||
* @param opts the `git_merge_file_options` instance to initialize.
|
||||
* @param version the version of the struct; you should pass
|
||||
* `GIT_MERGE_FILE_OPTIONS_VERSION` here.
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_file_init_options(
|
||||
git_merge_file_options *opts,
|
||||
unsigned int version);
|
||||
|
||||
typedef struct {
|
||||
/**
|
||||
* True if the output was automerged, false if the output contains
|
||||
* conflict markers.
|
||||
*/
|
||||
unsigned int automergeable;
|
||||
|
||||
/**
|
||||
* The path that the resultant merge file should use, or NULL if a
|
||||
* filename conflict would occur.
|
||||
*/
|
||||
const char *path;
|
||||
|
||||
/** The mode that the resultant merge file should use. */
|
||||
unsigned int mode;
|
||||
|
||||
/** The contents of the merge. */
|
||||
const char *ptr;
|
||||
|
||||
/** The length of the merge contents. */
|
||||
size_t len;
|
||||
} git_merge_file_result;
|
||||
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
git_merge_tree_flag_t flags;
|
||||
|
||||
/** Similarity to consider a file renamed (default 50) */
|
||||
/**
|
||||
* Similarity to consider a file renamed (default 50). If
|
||||
* `GIT_MERGE_TREE_FIND_RENAMES` is enabled, added files will be compared
|
||||
* with deleted files to determine their similarity. Files that are
|
||||
* more similar than the rename threshold (percentage-wise) will be
|
||||
* treated as a rename.
|
||||
*/
|
||||
unsigned int rename_threshold;
|
||||
|
||||
/** Maximum similarity sources to examine (overrides the
|
||||
* `merge.renameLimit` config) (default 200)
|
||||
/**
|
||||
* Maximum similarity sources to examine for renames (default 200).
|
||||
* If the number of rename candidates (add / delete pairs) is greater
|
||||
* than this value, inexact rename detection is aborted.
|
||||
*
|
||||
* This setting overrides the `merge.renameLimit` configuration value.
|
||||
*/
|
||||
unsigned int target_limit;
|
||||
|
||||
/** Pluggable similarity metric; pass NULL to use internal metric */
|
||||
git_diff_similarity_metric *metric;
|
||||
|
||||
/** Flags for automerging content. */
|
||||
git_merge_automerge_flags automerge_flags;
|
||||
} git_merge_tree_opts;
|
||||
|
||||
#define GIT_MERGE_TREE_OPTS_VERSION 1
|
||||
#define GIT_MERGE_TREE_OPTS_INIT {GIT_MERGE_TREE_OPTS_VERSION}
|
||||
/** Flags for handling conflicting content. */
|
||||
git_merge_file_favor_t file_favor;
|
||||
} git_merge_options;
|
||||
|
||||
#define GIT_MERGE_OPTIONS_VERSION 1
|
||||
#define GIT_MERGE_OPTIONS_INIT {GIT_MERGE_OPTIONS_VERSION}
|
||||
|
||||
/**
|
||||
* Option flags for `git_merge`.
|
||||
* Initializes a `git_merge_options` with default values. Equivalent to
|
||||
* creating an instance with GIT_MERGE_OPTIONS_INIT.
|
||||
*
|
||||
* GIT_MERGE_NO_FASTFORWARD - Do not fast-forward.
|
||||
* @param opts the `git_merge_options` instance to initialize.
|
||||
* @param version the version of the struct; you should pass
|
||||
* `GIT_MERGE_OPTIONS_VERSION` here.
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_init_options(
|
||||
git_merge_options *opts,
|
||||
unsigned int version);
|
||||
|
||||
/**
|
||||
* The results of `git_merge_analysis` indicate the merge opportunities.
|
||||
*/
|
||||
typedef enum {
|
||||
GIT_MERGE_NO_FASTFORWARD = 1,
|
||||
GIT_MERGE_FASTFORWARD_ONLY = 2,
|
||||
} git_merge_flags_t;
|
||||
/** No merge is possible. (Unused.) */
|
||||
GIT_MERGE_ANALYSIS_NONE = 0,
|
||||
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
/**
|
||||
* A "normal" merge; both HEAD and the given merge input have diverged
|
||||
* from their common ancestor. The divergent commits must be merged.
|
||||
*/
|
||||
GIT_MERGE_ANALYSIS_NORMAL = (1 << 0),
|
||||
|
||||
git_merge_flags_t merge_flags;
|
||||
git_merge_tree_opts merge_tree_opts;
|
||||
/**
|
||||
* All given merge inputs are reachable from HEAD, meaning the
|
||||
* repository is up-to-date and no merge needs to be performed.
|
||||
*/
|
||||
GIT_MERGE_ANALYSIS_UP_TO_DATE = (1 << 1),
|
||||
|
||||
git_checkout_opts checkout_opts;
|
||||
} git_merge_opts;
|
||||
/**
|
||||
* The given merge input is a fast-forward from HEAD and no merge
|
||||
* needs to be performed. Instead, the client can check out the
|
||||
* given merge input.
|
||||
*/
|
||||
GIT_MERGE_ANALYSIS_FASTFORWARD = (1 << 2),
|
||||
|
||||
#define GIT_MERGE_OPTS_VERSION 1
|
||||
#define GIT_MERGE_OPTS_INIT {GIT_MERGE_OPTS_VERSION, 0, GIT_MERGE_TREE_OPTS_INIT, GIT_CHECKOUT_OPTS_INIT}
|
||||
/**
|
||||
* The HEAD of the current repository is "unborn" and does not point to
|
||||
* a valid commit. No merge can be performed, but the caller may wish
|
||||
* to simply set HEAD to the target commit(s).
|
||||
*/
|
||||
GIT_MERGE_ANALYSIS_UNBORN = (1 << 3),
|
||||
} git_merge_analysis_t;
|
||||
|
||||
typedef enum {
|
||||
/*
|
||||
* No configuration was found that suggests a preferred behavior for
|
||||
* merge.
|
||||
*/
|
||||
GIT_MERGE_PREFERENCE_NONE = 0,
|
||||
|
||||
/**
|
||||
* There is a `merge.ff=false` configuration setting, suggesting that
|
||||
* the user does not want to allow a fast-forward merge.
|
||||
*/
|
||||
GIT_MERGE_PREFERENCE_NO_FASTFORWARD = (1 << 0),
|
||||
|
||||
/**
|
||||
* There is a `merge.ff=only` configuration setting, suggesting that
|
||||
* the user only wants fast-forward merges.
|
||||
*/
|
||||
GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY = (1 << 1),
|
||||
} git_merge_preference_t;
|
||||
|
||||
/**
|
||||
* Analyzes the given branch(es) and determines the opportunities for
|
||||
* merging them into the HEAD of the repository.
|
||||
*
|
||||
* @param analysis_out analysis enumeration that the result is written into
|
||||
* @param repo the repository to merge
|
||||
* @param their_heads the heads to merge into
|
||||
* @param their_heads_len the number of heads to merge
|
||||
* @return 0 on success or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_analysis(
|
||||
git_merge_analysis_t *analysis_out,
|
||||
git_merge_preference_t *preference_out,
|
||||
git_repository *repo,
|
||||
const git_merge_head **their_heads,
|
||||
size_t their_heads_len);
|
||||
|
||||
/**
|
||||
* Find a merge base between two commits
|
||||
@ -95,7 +312,7 @@ typedef struct {
|
||||
* @param repo the repository where the commits exist
|
||||
* @param one one of the commits
|
||||
* @param two the other commit
|
||||
* @return Zero on success; GIT_ENOTFOUND or -1 on failure.
|
||||
* @return 0 on success, GIT_ENOTFOUND if not found or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_base(
|
||||
git_oid *out,
|
||||
@ -119,27 +336,44 @@ GIT_EXTERN(int) git_merge_base_many(
|
||||
const git_oid input_array[]);
|
||||
|
||||
/**
|
||||
* Creates a `git_merge_head` from the given reference
|
||||
* Find a merge base in preparation for an octopus merge
|
||||
*
|
||||
* @param out the OID of a merge base considering all the commits
|
||||
* @param repo the repository where the commits exist
|
||||
* @param length The number of commits in the provided `input_array`
|
||||
* @param input_array oids of the commits
|
||||
* @return Zero on success; GIT_ENOTFOUND or -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_base_octopus(
|
||||
git_oid *out,
|
||||
git_repository *repo,
|
||||
size_t length,
|
||||
const git_oid input_array[]);
|
||||
|
||||
/**
|
||||
* Creates a `git_merge_head` from the given reference. The resulting
|
||||
* git_merge_head must be freed with `git_merge_head_free`.
|
||||
*
|
||||
* @param out pointer to store the git_merge_head result in
|
||||
* @param repo repository that contains the given reference
|
||||
* @param ref reference to use as a merge input
|
||||
* @return zero on success, -1 on failure.
|
||||
* @return 0 on success or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_head_from_ref(
|
||||
git_merge_head **out,
|
||||
git_repository *repo,
|
||||
git_reference *ref);
|
||||
const git_reference *ref);
|
||||
|
||||
/**
|
||||
* Creates a `git_merge_head` from the given fetch head data
|
||||
* Creates a `git_merge_head` from the given fetch head data. The resulting
|
||||
* git_merge_head must be freed with `git_merge_head_free`.
|
||||
*
|
||||
* @param out pointer to store the git_merge_head result in
|
||||
* @param repo repository that contains the given commit
|
||||
* @param branch_name name of the (remote) branch
|
||||
* @param remote_url url of the remote
|
||||
* @param oid the commit object id to use as a merge input
|
||||
* @return zero on success, -1 on failure.
|
||||
* @return 0 on success or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_head_from_fetchhead(
|
||||
git_merge_head **out,
|
||||
@ -149,29 +383,93 @@ GIT_EXTERN(int) git_merge_head_from_fetchhead(
|
||||
const git_oid *oid);
|
||||
|
||||
/**
|
||||
* Creates a `git_merge_head` from the given commit id
|
||||
* Creates a `git_merge_head` from the given commit id. The resulting
|
||||
* git_merge_head must be freed with `git_merge_head_free`.
|
||||
*
|
||||
* @param out pointer to store the git_merge_head result in
|
||||
* @param repo repository that contains the given commit
|
||||
* @param oid the commit object id to use as a merge input
|
||||
* @return zero on success, -1 on failure.
|
||||
* @param id the commit object id to use as a merge input
|
||||
* @return 0 on success or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_head_from_oid(
|
||||
GIT_EXTERN(int) git_merge_head_from_id(
|
||||
git_merge_head **out,
|
||||
git_repository *repo,
|
||||
const git_oid *oid);
|
||||
const git_oid *id);
|
||||
|
||||
/**
|
||||
* Frees a `git_merge_head`
|
||||
* Gets the commit ID that the given `git_merge_head` refers to.
|
||||
*
|
||||
* @param head the given merge head
|
||||
* @return commit id
|
||||
*/
|
||||
GIT_EXTERN(const git_oid *) git_merge_head_id(
|
||||
const git_merge_head *head);
|
||||
|
||||
/**
|
||||
* Frees a `git_merge_head`.
|
||||
*
|
||||
* @param head merge head to free
|
||||
*/
|
||||
GIT_EXTERN(void) git_merge_head_free(
|
||||
git_merge_head *head);
|
||||
|
||||
/**
|
||||
* Merge two files as they exist in the in-memory data structures, using
|
||||
* the given common ancestor as the baseline, producing a
|
||||
* `git_merge_file_result` that reflects the merge result. The
|
||||
* `git_merge_file_result` must be freed with `git_merge_file_result_free`.
|
||||
*
|
||||
* Note that this function does not reference a repository and any
|
||||
* configuration must be passed as `git_merge_file_options`.
|
||||
*
|
||||
* @param out The git_merge_file_result to be filled in
|
||||
* @param ancestor The contents of the ancestor file
|
||||
* @param ours The contents of the file in "our" side
|
||||
* @param theirs The contents of the file in "their" side
|
||||
* @param opts The merge file options or `NULL` for defaults
|
||||
* @return 0 on success or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_file(
|
||||
git_merge_file_result *out,
|
||||
const git_merge_file_input *ancestor,
|
||||
const git_merge_file_input *ours,
|
||||
const git_merge_file_input *theirs,
|
||||
const git_merge_file_options *opts);
|
||||
|
||||
/**
|
||||
* Merge two files as they exist in the index, using the given common
|
||||
* ancestor as the baseline, producing a `git_merge_file_result` that
|
||||
* reflects the merge result. The `git_merge_file_result` must be freed with
|
||||
* `git_merge_file_result_free`.
|
||||
*
|
||||
* @param out The git_merge_file_result to be filled in
|
||||
* @param repo The repository
|
||||
* @param ancestor The index entry for the ancestor file (stage level 1)
|
||||
* @param ours The index entry for our file (stage level 2)
|
||||
* @param theirs The index entry for their file (stage level 3)
|
||||
* @param opts The merge file options or NULL
|
||||
* @return 0 on success or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_file_from_index(
|
||||
git_merge_file_result *out,
|
||||
git_repository *repo,
|
||||
const git_index_entry *ancestor,
|
||||
const git_index_entry *ours,
|
||||
const git_index_entry *theirs,
|
||||
const git_merge_file_options *opts);
|
||||
|
||||
/**
|
||||
* Frees a `git_merge_file_result`.
|
||||
*
|
||||
* @param result The result to free or `NULL`
|
||||
*/
|
||||
GIT_EXTERN(void) git_merge_file_result_free(git_merge_file_result *result);
|
||||
|
||||
/**
|
||||
* Merge two trees, producing a `git_index` that reflects the result of
|
||||
* the merge.
|
||||
* the merge. The index may be written as-is to the working directory
|
||||
* or checked out. If the index is to be converted to a tree, the caller
|
||||
* should resolve any conflicts that arose as part of the merge.
|
||||
*
|
||||
* The returned index must be freed explicitly with `git_index_free`.
|
||||
*
|
||||
@ -181,7 +479,7 @@ GIT_EXTERN(void) git_merge_head_free(
|
||||
* @param our_tree the tree that reflects the destination tree
|
||||
* @param their_tree the tree to merge in to `our_tree`
|
||||
* @param opts the merge tree options (or null for defaults)
|
||||
* @return zero on success, -1 on failure.
|
||||
* @return 0 on success or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_trees(
|
||||
git_index **out,
|
||||
@ -189,44 +487,49 @@ GIT_EXTERN(int) git_merge_trees(
|
||||
const git_tree *ancestor_tree,
|
||||
const git_tree *our_tree,
|
||||
const git_tree *their_tree,
|
||||
const git_merge_tree_opts *opts);
|
||||
const git_merge_options *opts);
|
||||
|
||||
/**
|
||||
* Merges the given commits into HEAD, producing a new commit.
|
||||
* Merge two commits, producing a `git_index` that reflects the result of
|
||||
* the merge. The index may be written as-is to the working directory
|
||||
* or checked out. If the index is to be converted to a tree, the caller
|
||||
* should resolve any conflicts that arose as part of the merge.
|
||||
*
|
||||
* The returned index must be freed explicitly with `git_index_free`.
|
||||
*
|
||||
* @param out pointer to store the index result in
|
||||
* @param repo repository that contains the given trees
|
||||
* @param our_commit the commit that reflects the destination tree
|
||||
* @param their_commit the commit to merge in to `our_commit`
|
||||
* @param opts the merge tree options (or null for defaults)
|
||||
* @return 0 on success or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_commits(
|
||||
git_index **out,
|
||||
git_repository *repo,
|
||||
const git_commit *our_commit,
|
||||
const git_commit *their_commit,
|
||||
const git_merge_options *opts);
|
||||
|
||||
/**
|
||||
* Merges the given commit(s) into HEAD, writing the results into the working
|
||||
* directory. Any changes are staged for commit and any conflicts are written
|
||||
* to the index. Callers should inspect the repository's index after this
|
||||
* completes, resolve any conflicts and prepare a commit.
|
||||
*
|
||||
* @param out the results of the merge
|
||||
* @param repo the repository to merge
|
||||
* @param merge_heads the heads to merge into
|
||||
* @param merge_heads_len the number of heads to merge
|
||||
* @param flags merge flags
|
||||
* @param their_heads the heads to merge into
|
||||
* @param their_heads_len the number of heads to merge
|
||||
* @param merge_opts merge options
|
||||
* @param checkout_opts checkout options
|
||||
* @return 0 on success or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge(
|
||||
git_merge_result **out,
|
||||
git_repository *repo,
|
||||
const git_merge_head **their_heads,
|
||||
size_t their_heads_len,
|
||||
const git_merge_opts *opts);
|
||||
|
||||
/**
|
||||
* Returns true if a merge is up-to-date (we were asked to merge the target
|
||||
* into itself.)
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_result_is_uptodate(git_merge_result *merge_result);
|
||||
|
||||
/**
|
||||
* Returns true if a merge is eligible for fastforward
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_result_is_fastforward(git_merge_result *merge_result);
|
||||
|
||||
/**
|
||||
* Gets the fast-forward OID if the merge was a fastforward.
|
||||
*
|
||||
* @param out the OID of the fast-forward
|
||||
* @param merge_result the results of the merge
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_result_fastforward_oid(git_oid *out, git_merge_result *merge_result);
|
||||
|
||||
GIT_EXTERN(void) git_merge_result_free(git_merge_result *merge_result);
|
||||
const git_merge_options *merge_opts,
|
||||
const git_checkout_options *checkout_opts);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
|
@ -8,6 +8,7 @@
|
||||
#define INCLUDE_git_message_h__
|
||||
|
||||
#include "common.h"
|
||||
#include "buffer.h"
|
||||
|
||||
/**
|
||||
* @file git2/message.h
|
||||
@ -23,25 +24,19 @@ GIT_BEGIN_DECL
|
||||
*
|
||||
* Optionally, can remove lines starting with a "#".
|
||||
*
|
||||
* @param out The user-allocated buffer which will be filled with the
|
||||
* cleaned up message. Pass NULL if you just want to get the needed
|
||||
* size of the prettified message as the output value.
|
||||
*
|
||||
* @param out_size Size of the `out` buffer in bytes.
|
||||
* @param out The user-allocated git_buf which will be filled with the
|
||||
* cleaned up message.
|
||||
*
|
||||
* @param message The message to be prettified.
|
||||
*
|
||||
* @param strip_comments Non-zero to remove lines starting with "#", 0 to
|
||||
* leave them in.
|
||||
* @param strip_comments Non-zero to remove comment lines, 0 to leave them in.
|
||||
*
|
||||
* @return -1 on error, else number of characters in prettified message
|
||||
* including the trailing NUL byte
|
||||
* @param comment_char Comment character. Lines starting with this character
|
||||
* are considered to be comments and removed if `strip_comments` is non-zero.
|
||||
*
|
||||
* @return 0 or an error code.
|
||||
*/
|
||||
GIT_EXTERN(int) git_message_prettify(
|
||||
char *out,
|
||||
size_t out_size,
|
||||
const char *message,
|
||||
int strip_comments);
|
||||
GIT_EXTERN(int) git_message_prettify(git_buf *out, const char *message, int strip_comments, char comment_char);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
|
@ -41,6 +41,11 @@ struct git_remote_head {
|
||||
git_oid oid;
|
||||
git_oid loid;
|
||||
char *name;
|
||||
/**
|
||||
* If the server send a symref mapping for this ref, this will
|
||||
* point to the target.
|
||||
*/
|
||||
char *symref_target;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -106,12 +106,12 @@ GIT_EXTERN(const char *) git_note_message(const git_note *note);
|
||||
|
||||
|
||||
/**
|
||||
* Get the note object OID
|
||||
* Get the note object's id
|
||||
*
|
||||
* @param note the note
|
||||
* @return the note object OID
|
||||
* @return the note object's id
|
||||
*/
|
||||
GIT_EXTERN(const git_oid *) git_note_oid(const git_note *note);
|
||||
GIT_EXTERN(const git_oid *) git_note_id(const git_note *note);
|
||||
|
||||
/**
|
||||
* Add a note for an object
|
||||
@ -189,7 +189,7 @@ GIT_EXTERN(int) git_note_default_ref(const char **out, git_repository *repo);
|
||||
*
|
||||
* @param payload Extra parameter to callback function.
|
||||
*
|
||||
* @return 0 on success, GIT_EUSER on non-zero callback, or error code
|
||||
* @return 0 on success, non-zero callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_note_foreach(
|
||||
git_repository *repo,
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "common.h"
|
||||
#include "types.h"
|
||||
#include "oid.h"
|
||||
#include "buffer.h"
|
||||
|
||||
/**
|
||||
* @file git2/object.h
|
||||
@ -103,6 +104,20 @@ GIT_EXTERN(int) git_object_lookup_bypath(
|
||||
*/
|
||||
GIT_EXTERN(const git_oid *) git_object_id(const git_object *obj);
|
||||
|
||||
/**
|
||||
* Get a short abbreviated OID string for the object
|
||||
*
|
||||
* This starts at the "core.abbrev" length (default 7 characters) and
|
||||
* iteratively extends to a longer string if that length is ambiguous.
|
||||
* The result will be unambiguous (at least until new objects are added to
|
||||
* the repository).
|
||||
*
|
||||
* @param out Buffer to write string into
|
||||
* @param obj The object to get an ID for
|
||||
* @return 0 on success, <0 for error
|
||||
*/
|
||||
GIT_EXTERN(int) git_object_short_id(git_buf *out, const git_object *obj);
|
||||
|
||||
/**
|
||||
* Get the object type of an object
|
||||
*
|
||||
@ -143,7 +158,7 @@ GIT_EXTERN(git_repository *) git_object_owner(const git_object *obj);
|
||||
GIT_EXTERN(void) git_object_free(git_object *object);
|
||||
|
||||
/**
|
||||
* Convert an object type to it's string representation.
|
||||
* Convert an object type to its string representation.
|
||||
*
|
||||
* The result is a pointer to a string in static memory and
|
||||
* should not be free()'ed.
|
||||
|
@ -158,6 +158,19 @@ GIT_EXTERN(int) git_odb_read_header(size_t *len_out, git_otype *type_out, git_od
|
||||
*/
|
||||
GIT_EXTERN(int) git_odb_exists(git_odb *db, const git_oid *id);
|
||||
|
||||
/**
|
||||
* Determine if objects can be found in the object database from a short OID.
|
||||
*
|
||||
* @param out The full OID of the found object if just one is found.
|
||||
* @param db The database to be searched for the given object.
|
||||
* @param short_id A prefix of the id of the object to read.
|
||||
* @param len The length of the prefix.
|
||||
* @return 0 if found, GIT_ENOTFOUND if not found, GIT_EAMBIGUOUS if multiple
|
||||
* matches were found, other value < 0 if there was a read error.
|
||||
*/
|
||||
GIT_EXTERN(int) git_odb_exists_prefix(
|
||||
git_oid *out, git_odb *db, const git_oid *short_id, size_t len);
|
||||
|
||||
/**
|
||||
* Refresh the object database to load newly added files.
|
||||
*
|
||||
@ -189,7 +202,7 @@ GIT_EXTERN(int) git_odb_refresh(struct git_odb *db);
|
||||
* @param db database to use
|
||||
* @param cb the callback to call for each object
|
||||
* @param payload data to pass to the callback
|
||||
* @return 0 on success, GIT_EUSER on non-zero callback, or error code
|
||||
* @return 0 on success, non-zero callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_odb_foreach(git_odb *db, git_odb_foreach_cb cb, void *payload);
|
||||
|
||||
@ -325,7 +338,7 @@ GIT_EXTERN(int) git_odb_open_rstream(git_odb_stream **out, git_odb *db, const gi
|
||||
GIT_EXTERN(int) git_odb_write_pack(
|
||||
git_odb_writepack **out,
|
||||
git_odb *db,
|
||||
git_transfer_progress_callback progress_cb,
|
||||
git_transfer_progress_cb progress_cb,
|
||||
void *progress_payload);
|
||||
|
||||
/**
|
||||
|
@ -167,10 +167,7 @@ GIT_EXTERN(int) git_oid_cmp(const git_oid *a, const git_oid *b);
|
||||
* @param b second oid structure.
|
||||
* @return true if equal, false otherwise
|
||||
*/
|
||||
GIT_INLINE(int) git_oid_equal(const git_oid *a, const git_oid *b)
|
||||
{
|
||||
return !git_oid_cmp(a, b);
|
||||
}
|
||||
GIT_EXTERN(int) git_oid_equal(const git_oid *a, const git_oid *b);
|
||||
|
||||
/**
|
||||
* Compare the first 'len' hexadecimal characters (packets of 4 bits)
|
||||
|
@ -52,7 +52,7 @@ typedef enum {
|
||||
GIT_PACKBUILDER_ADDING_OBJECTS = 0,
|
||||
GIT_PACKBUILDER_DELTAFICATION = 1,
|
||||
} git_packbuilder_stage_t;
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a new packbuilder
|
||||
*
|
||||
@ -114,6 +114,17 @@ GIT_EXTERN(int) git_packbuilder_insert_tree(git_packbuilder *pb, const git_oid *
|
||||
*/
|
||||
GIT_EXTERN(int) git_packbuilder_insert_commit(git_packbuilder *pb, const git_oid *id);
|
||||
|
||||
/**
|
||||
* Write the contents of the packfile to an in-memory buffer
|
||||
*
|
||||
* The contents of the buffer will become a valid packfile, even though there
|
||||
* will be no attached index
|
||||
*
|
||||
* @param buf Buffer where to write the packfile
|
||||
* @param pb The packbuilder
|
||||
*/
|
||||
GIT_EXTERN(int) git_packbuilder_write_buf(git_buf *buf, git_packbuilder *pb);
|
||||
|
||||
/**
|
||||
* Write the new pack and corresponding index file to path.
|
||||
*
|
||||
@ -129,7 +140,7 @@ GIT_EXTERN(int) git_packbuilder_write(
|
||||
git_packbuilder *pb,
|
||||
const char *path,
|
||||
unsigned int mode,
|
||||
git_transfer_progress_callback progress_cb,
|
||||
git_transfer_progress_cb progress_cb,
|
||||
void *progress_cb_payload);
|
||||
|
||||
/**
|
||||
@ -143,6 +154,7 @@ GIT_EXTERN(int) git_packbuilder_write(
|
||||
GIT_EXTERN(const git_oid *) git_packbuilder_hash(git_packbuilder *pb);
|
||||
|
||||
typedef int (*git_packbuilder_foreach_cb)(void *buf, size_t size, void *payload);
|
||||
|
||||
/**
|
||||
* Create the new pack and pass each object to the callback
|
||||
*
|
||||
|
@ -105,6 +105,34 @@ GIT_EXTERN(int) git_patch_from_blob_and_buffer(
|
||||
const char *buffer_as_path,
|
||||
const git_diff_options *opts);
|
||||
|
||||
/**
|
||||
* Directly generate a patch from the difference between two buffers.
|
||||
*
|
||||
* This is just like `git_diff_buffers()` except it generates a patch
|
||||
* object for the difference instead of directly making callbacks. You can
|
||||
* use the standard `git_patch` accessor functions to read the patch
|
||||
* data, and you must call `git_patch_free()` on the patch when done.
|
||||
*
|
||||
* @param out The generated patch; NULL on error
|
||||
* @param old_buffer Raw data for old side of diff, or NULL for empty
|
||||
* @param old_len Length of the raw data for old side of the diff
|
||||
* @param old_as_path Treat old buffer as if it had this filename; can be NULL
|
||||
* @param new_buffer Raw data for new side of diff, or NULL for empty
|
||||
* @param new_len Length of raw data for new side of diff
|
||||
* @param new_as_path Treat buffer as if it had this filename; can be NULL
|
||||
* @param opts Options for diff, or NULL for default options
|
||||
* @return 0 on success or error code < 0
|
||||
*/
|
||||
GIT_EXTERN(int) git_patch_from_buffers(
|
||||
git_patch **out,
|
||||
const void *old_buffer,
|
||||
size_t old_len,
|
||||
const char *old_as_path,
|
||||
const char *new_buffer,
|
||||
size_t new_len,
|
||||
const char *new_as_path,
|
||||
const git_diff_options *opts);
|
||||
|
||||
/**
|
||||
* Free a git_patch object.
|
||||
*/
|
||||
@ -113,12 +141,12 @@ GIT_EXTERN(void) git_patch_free(git_patch *patch);
|
||||
/**
|
||||
* Get the delta associated with a patch
|
||||
*/
|
||||
GIT_EXTERN(const git_diff_delta *) git_patch_get_delta(git_patch *patch);
|
||||
GIT_EXTERN(const git_diff_delta *) git_patch_get_delta(const git_patch *patch);
|
||||
|
||||
/**
|
||||
* Get the number of hunks in a patch
|
||||
*/
|
||||
GIT_EXTERN(size_t) git_patch_num_hunks(git_patch *patch);
|
||||
GIT_EXTERN(size_t) git_patch_num_hunks(const git_patch *patch);
|
||||
|
||||
/**
|
||||
* Get line counts of each type in a patch.
|
||||
@ -169,7 +197,7 @@ GIT_EXTERN(int) git_patch_get_hunk(
|
||||
* @return Number of lines in hunk or -1 if invalid hunk index
|
||||
*/
|
||||
GIT_EXTERN(int) git_patch_num_lines_in_hunk(
|
||||
git_patch *patch,
|
||||
const git_patch *patch,
|
||||
size_t hunk_idx);
|
||||
|
||||
/**
|
||||
@ -218,13 +246,13 @@ GIT_EXTERN(size_t) git_patch_size(
|
||||
* Serialize the patch to text via callback.
|
||||
*
|
||||
* Returning a non-zero value from the callback will terminate the iteration
|
||||
* and cause this return `GIT_EUSER`.
|
||||
* and return that value to the caller.
|
||||
*
|
||||
* @param patch A git_patch representing changes to one file
|
||||
* @param print_cb Callback function to output lines of the patch. Will be
|
||||
* called for file headers, hunk headers, and diff lines.
|
||||
* @param payload Reference pointer that will be passed to your callbacks.
|
||||
* @return 0 on success, GIT_EUSER on non-zero callback, or error code
|
||||
* @return 0 on success, non-zero callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_patch_print(
|
||||
git_patch *patch,
|
||||
@ -234,15 +262,14 @@ GIT_EXTERN(int) git_patch_print(
|
||||
/**
|
||||
* Get the content of a patch as a single diff text.
|
||||
*
|
||||
* @param string Allocated string; caller must free.
|
||||
* @param out The git_buf to be filled in
|
||||
* @param patch A git_patch representing changes to one file
|
||||
* @return 0 on success, <0 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_patch_to_str(
|
||||
char **string,
|
||||
GIT_EXTERN(int) git_patch_to_buf(
|
||||
git_buf *out,
|
||||
git_patch *patch);
|
||||
|
||||
|
||||
GIT_END_DECL
|
||||
|
||||
/**@}*/
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include "strarray.h"
|
||||
#include "diff.h"
|
||||
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Compiled pathspec
|
||||
*/
|
||||
@ -257,4 +259,5 @@ GIT_EXTERN(size_t) git_pathspec_match_list_failed_entrycount(
|
||||
GIT_EXTERN(const char *) git_pathspec_match_list_failed_entry(
|
||||
const git_pathspec_match_list *m, size_t pos);
|
||||
|
||||
GIT_END_DECL
|
||||
#endif
|
||||
|
@ -39,6 +39,19 @@ typedef struct {
|
||||
#define GIT_PUSH_OPTIONS_VERSION 1
|
||||
#define GIT_PUSH_OPTIONS_INIT { GIT_PUSH_OPTIONS_VERSION }
|
||||
|
||||
/**
|
||||
* Initializes a `git_push_options` with default values. Equivalent to
|
||||
* creating an instance with GIT_PUSH_OPTIONS_INIT.
|
||||
*
|
||||
* @param opts the `git_push_options` instance to initialize.
|
||||
* @param version the version of the struct; you should pass
|
||||
* `GIT_PUSH_OPTIONS_VERSION` here.
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_push_init_options(
|
||||
git_push_options *opts,
|
||||
unsigned int version);
|
||||
|
||||
/** Push network progress notification function */
|
||||
typedef int (*git_push_transfer_progress)(
|
||||
unsigned int current,
|
||||
@ -103,10 +116,16 @@ GIT_EXTERN(int) git_push_add_refspec(git_push *push, const char *refspec);
|
||||
* Update remote tips after a push
|
||||
*
|
||||
* @param push The push object
|
||||
* @param signature The identity to use when updating reflogs
|
||||
* @param reflog_message The message to insert into the reflogs. If NULL, the
|
||||
* default is "update by push".
|
||||
*
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_push_update_tips(git_push *push);
|
||||
GIT_EXTERN(int) git_push_update_tips(
|
||||
git_push *push,
|
||||
const git_signature *signature,
|
||||
const char *reflog_message);
|
||||
|
||||
/**
|
||||
* Actually push all given refspecs
|
||||
@ -129,20 +148,22 @@ GIT_EXTERN(int) git_push_finish(git_push *push);
|
||||
*
|
||||
* @return true if remote side successfully unpacked, false otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_push_unpack_ok(git_push *push);
|
||||
GIT_EXTERN(int) git_push_unpack_ok(const git_push *push);
|
||||
|
||||
/**
|
||||
* Call callback `cb' on each status
|
||||
* Invoke callback `cb' on each status entry
|
||||
*
|
||||
* For each of the updated references, we receive a status report in the
|
||||
* form of `ok refs/heads/master` or `ng refs/heads/master <msg>`.
|
||||
* `msg != NULL` means the reference has not been updated for the given
|
||||
* reason.
|
||||
*
|
||||
* Return a non-zero value from the callback to stop the loop.
|
||||
*
|
||||
* @param push The push object
|
||||
* @param cb The callback to call on each object
|
||||
*
|
||||
* @return 0 on success, GIT_EUSER on non-zero callback, or error code
|
||||
* @return 0 on success, non-zero callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_push_status_foreach(git_push *push,
|
||||
int (*cb)(const char *ref, const char *msg, void *data),
|
||||
|
@ -47,7 +47,7 @@ GIT_EXTERN(int) git_reflog_read(git_reflog **out, git_repository *repo, const c
|
||||
GIT_EXTERN(int) git_reflog_write(git_reflog *reflog);
|
||||
|
||||
/**
|
||||
* Add a new entry to the reflog.
|
||||
* Add a new entry to the in-memory reflog.
|
||||
*
|
||||
* `msg` is optional and can be NULL.
|
||||
*
|
||||
@ -59,23 +59,6 @@ GIT_EXTERN(int) git_reflog_write(git_reflog *reflog);
|
||||
*/
|
||||
GIT_EXTERN(int) git_reflog_append(git_reflog *reflog, const git_oid *id, const git_signature *committer, const char *msg);
|
||||
|
||||
/**
|
||||
* Add a new entry to the named reflog.
|
||||
*
|
||||
* This utility function loads the named reflog, appends to it and
|
||||
* writes it back out to the backend.
|
||||
*
|
||||
* `msg` is optional and can be NULL.
|
||||
*
|
||||
* @param repo the repository to act on
|
||||
* @param name the reflog's name
|
||||
* @param id the OID the reference is now pointing to
|
||||
* @param committer the signature of the committer
|
||||
* @param msg the reflog message
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_reflog_append_to(git_repository *repo, const char *name, const git_oid *id, const git_signature *committer, const char *msg);
|
||||
|
||||
/**
|
||||
* Rename a reflog
|
||||
*
|
||||
@ -86,7 +69,7 @@ GIT_EXTERN(int) git_reflog_append_to(git_repository *repo, const char *name, con
|
||||
*
|
||||
* @param repo the repository
|
||||
* @param old_name the old name of the reference
|
||||
* @param new_name the new name of the reference
|
||||
* @param name the new name of the reference
|
||||
* @return 0 on success, GIT_EINVALIDSPEC or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_reflog_rename(git_repository *repo, const char *old_name, const char *name);
|
||||
|
@ -27,7 +27,7 @@ GIT_BEGIN_DECL
|
||||
* The returned reference must be freed by the user.
|
||||
*
|
||||
* The name will be checked for validity.
|
||||
* See `git_reference_create_symbolic()` for rules about valid names.
|
||||
* See `git_reference_symbolic_create()` for rules about valid names.
|
||||
*
|
||||
* @param out pointer to the looked-up reference
|
||||
* @param repo the repository to look up the reference
|
||||
@ -67,6 +67,48 @@ GIT_EXTERN(int) git_reference_name_to_id(
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_dwim(git_reference **out, git_repository *repo, const char *shorthand);
|
||||
|
||||
/**
|
||||
* Conditionally create a new symbolic reference.
|
||||
*
|
||||
* A symbolic reference is a reference name that refers to another
|
||||
* reference name. If the other name moves, the symbolic name will move,
|
||||
* too. As a simple example, the "HEAD" reference might refer to
|
||||
* "refs/heads/master" while on the "master" branch of a repository.
|
||||
*
|
||||
* The symbolic reference will be created in the repository and written to
|
||||
* the disk. The generated reference object must be freed by the user.
|
||||
*
|
||||
* Valid reference names must follow one of two patterns:
|
||||
*
|
||||
* 1. Top-level names must contain only capital letters and underscores,
|
||||
* and must begin and end with a letter. (e.g. "HEAD", "ORIG_HEAD").
|
||||
* 2. Names prefixed with "refs/" can be almost anything. You must avoid
|
||||
* the characters '~', '^', ':', '\\', '?', '[', and '*', and the
|
||||
* sequences ".." and "@{" which have special meaning to revparse.
|
||||
*
|
||||
* This function will return an error if a reference already exists with the
|
||||
* given name unless `force` is true, in which case it will be overwritten.
|
||||
*
|
||||
* The signature and message for the reflog will be ignored if the
|
||||
* reference does not belong in the standard set (HEAD, branches and
|
||||
* remote-tracking branches) and it does not have a reflog.
|
||||
*
|
||||
* It will return GIT_EMODIFIED if the reference's value at the time
|
||||
* of updating does not match the one passed through `current_value`
|
||||
* (i.e. if the ref has changed since the user read it).
|
||||
*
|
||||
* @param out Pointer to the newly created reference
|
||||
* @param repo Repository where that reference will live
|
||||
* @param name The name of the reference
|
||||
* @param target The target of the reference
|
||||
* @param force Overwrite existing references
|
||||
* @param current_value The expected value of the reference when updating
|
||||
* @param signature The identity that will used to populate the reflog entry
|
||||
* @param log_message The one line long message to be appended to the reflog
|
||||
* @return 0 on success, GIT_EEXISTS, GIT_EINVALIDSPEC, GIT_EMODIFIED or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_symbolic_create_matching(git_reference **out, git_repository *repo, const char *name, const char *target, int force, const char *current_value, const git_signature *signature, const char *log_message);
|
||||
|
||||
/**
|
||||
* Create a new symbolic reference.
|
||||
*
|
||||
@ -89,14 +131,20 @@ GIT_EXTERN(int) git_reference_dwim(git_reference **out, git_repository *repo, co
|
||||
* This function will return an error if a reference already exists with the
|
||||
* given name unless `force` is true, in which case it will be overwritten.
|
||||
*
|
||||
* The signature and message for the reflog will be ignored if the
|
||||
* reference does not belong in the standard set (HEAD, branches and
|
||||
* remote-tracking branches) and it does not have a reflog.
|
||||
*
|
||||
* @param out Pointer to the newly created reference
|
||||
* @param repo Repository where that reference will live
|
||||
* @param name The name of the reference
|
||||
* @param target The target of the reference
|
||||
* @param force Overwrite existing references
|
||||
* @param signature The identity that will used to populate the reflog entry
|
||||
* @param log_message The one line long message to be appended to the reflog
|
||||
* @return 0 on success, GIT_EEXISTS, GIT_EINVALIDSPEC or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_symbolic_create(git_reference **out, git_repository *repo, const char *name, const char *target, int force);
|
||||
GIT_EXTERN(int) git_reference_symbolic_create(git_reference **out, git_repository *repo, const char *name, const char *target, int force, const git_signature *signature, const char *log_message);
|
||||
|
||||
/**
|
||||
* Create a new direct reference.
|
||||
@ -121,14 +169,64 @@ GIT_EXTERN(int) git_reference_symbolic_create(git_reference **out, git_repositor
|
||||
* This function will return an error if a reference already exists with the
|
||||
* given name unless `force` is true, in which case it will be overwritten.
|
||||
*
|
||||
* The signature and message for the reflog will be ignored if the
|
||||
* reference does not belong in the standard set (HEAD, branches and
|
||||
* remote-tracking branches) and and it does not have a reflog.
|
||||
*
|
||||
* @param out Pointer to the newly created reference
|
||||
* @param repo Repository where that reference will live
|
||||
* @param name The name of the reference
|
||||
* @param id The object id pointed to by the reference.
|
||||
* @param force Overwrite existing references
|
||||
* @param signature The identity that will used to populate the reflog entry
|
||||
* @param log_message The one line long message to be appended to the reflog
|
||||
* @return 0 on success, GIT_EEXISTS, GIT_EINVALIDSPEC or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_create(git_reference **out, git_repository *repo, const char *name, const git_oid *id, int force);
|
||||
GIT_EXTERN(int) git_reference_create(git_reference **out, git_repository *repo, const char *name, const git_oid *id, int force, const git_signature *signature, const char *log_message);
|
||||
|
||||
/**
|
||||
* Conditionally create new direct reference
|
||||
*
|
||||
* A direct reference (also called an object id reference) refers directly
|
||||
* to a specific object id (a.k.a. OID or SHA) in the repository. The id
|
||||
* permanently refers to the object (although the reference itself can be
|
||||
* moved). For example, in libgit2 the direct ref "refs/tags/v0.17.0"
|
||||
* refers to OID 5b9fac39d8a76b9139667c26a63e6b3f204b3977.
|
||||
*
|
||||
* The direct reference will be created in the repository and written to
|
||||
* the disk. The generated reference object must be freed by the user.
|
||||
*
|
||||
* Valid reference names must follow one of two patterns:
|
||||
*
|
||||
* 1. Top-level names must contain only capital letters and underscores,
|
||||
* and must begin and end with a letter. (e.g. "HEAD", "ORIG_HEAD").
|
||||
* 2. Names prefixed with "refs/" can be almost anything. You must avoid
|
||||
* the characters '~', '^', ':', '\\', '?', '[', and '*', and the
|
||||
* sequences ".." and "@{" which have special meaning to revparse.
|
||||
*
|
||||
* This function will return an error if a reference already exists with the
|
||||
* given name unless `force` is true, in which case it will be overwritten.
|
||||
*
|
||||
* The signature and message for the reflog will be ignored if the
|
||||
* reference does not belong in the standard set (HEAD, branches and
|
||||
* remote-tracking branches) and and it does not have a reflog.
|
||||
*
|
||||
* It will return GIT_EMODIFIED if the reference's value at the time
|
||||
* of updating does not match the one passed through `current_id`
|
||||
* (i.e. if the ref has changed since the user read it).
|
||||
*
|
||||
* @param out Pointer to the newly created reference
|
||||
* @param repo Repository where that reference will live
|
||||
* @param name The name of the reference
|
||||
* @param id The object id pointed to by the reference.
|
||||
* @param force Overwrite existing references
|
||||
* @param current_id The expected value of the reference at the time of update
|
||||
* @param signature The identity that will used to populate the reflog entry
|
||||
* @param log_message The one line long message to be appended to the reflog
|
||||
* @return 0 on success, GIT_EMODIFIED if the value of the reference
|
||||
* has changed, GIT_EEXISTS, GIT_EINVALIDSPEC or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_create_matching(git_reference **out, git_repository *repo, const char *name, const git_oid *id, int force, const git_oid *current_id, const git_signature *signature, const char *log_message);
|
||||
|
||||
/**
|
||||
* Get the OID pointed to by a direct reference.
|
||||
@ -179,7 +277,7 @@ GIT_EXTERN(git_ref_t) git_reference_type(const git_reference *ref);
|
||||
/**
|
||||
* Get the full name of a reference.
|
||||
*
|
||||
* See `git_reference_create_symbolic()` for rules about valid names.
|
||||
* See `git_reference_symbolic_create()` for rules about valid names.
|
||||
*
|
||||
* @param ref The reference
|
||||
* @return the full name for the ref
|
||||
@ -220,20 +318,28 @@ GIT_EXTERN(git_repository *) git_reference_owner(const git_reference *ref);
|
||||
* The new reference will be written to disk, overwriting the given reference.
|
||||
*
|
||||
* The target name will be checked for validity.
|
||||
* See `git_reference_create_symbolic()` for rules about valid names.
|
||||
* See `git_reference_symbolic_create()` for rules about valid names.
|
||||
*
|
||||
* The signature and message for the reflog will be ignored if the
|
||||
* reference does not belong in the standard set (HEAD, branches and
|
||||
* remote-tracking branches) and and it does not have a reflog.
|
||||
*
|
||||
* @param out Pointer to the newly created reference
|
||||
* @param ref The reference
|
||||
* @param target The new target for the reference
|
||||
* @param signature The identity that will used to populate the reflog entry
|
||||
* @param log_message The one line long message to be appended to the reflog
|
||||
* @return 0 on success, GIT_EINVALIDSPEC or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_symbolic_set_target(
|
||||
git_reference **out,
|
||||
git_reference *ref,
|
||||
const char *target);
|
||||
const char *target,
|
||||
const git_signature *signature,
|
||||
const char *log_message);
|
||||
|
||||
/**
|
||||
* Create a new reference with the same name as the given reference but a
|
||||
* Conditionally create a new reference with the same name as the given reference but a
|
||||
* different OID target. The reference must be a direct reference, otherwise
|
||||
* this will fail.
|
||||
*
|
||||
@ -242,12 +348,17 @@ GIT_EXTERN(int) git_reference_symbolic_set_target(
|
||||
* @param out Pointer to the newly created reference
|
||||
* @param ref The reference
|
||||
* @param id The new target OID for the reference
|
||||
* @return 0 or an error code
|
||||
* @param signature The identity that will used to populate the reflog entry
|
||||
* @param log_message The one line long message to be appended to the reflog
|
||||
* @return 0 on success, GIT_EMODIFIED if the value of the reference
|
||||
* has changed since it was read, or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_set_target(
|
||||
git_reference **out,
|
||||
git_reference *ref,
|
||||
const git_oid *id);
|
||||
const git_oid *id,
|
||||
const git_signature *signature,
|
||||
const char *log_message);
|
||||
|
||||
/**
|
||||
* Rename an existing reference.
|
||||
@ -255,7 +366,7 @@ GIT_EXTERN(int) git_reference_set_target(
|
||||
* This method works for both direct and symbolic references.
|
||||
*
|
||||
* The new name will be checked for validity.
|
||||
* See `git_reference_create_symbolic()` for rules about valid names.
|
||||
* See `git_reference_symbolic_create()` for rules about valid names.
|
||||
*
|
||||
* If the `force` flag is not enabled, and there's already
|
||||
* a reference with the given name, the renaming will fail.
|
||||
@ -268,6 +379,8 @@ GIT_EXTERN(int) git_reference_set_target(
|
||||
* @param ref The reference to rename
|
||||
* @param new_name The new name for the reference
|
||||
* @param force Overwrite an existing reference
|
||||
* @param signature The identity that will used to populate the reflog entry
|
||||
* @param log_message The one line long message to be appended to the reflog
|
||||
* @return 0 on success, GIT_EINVALIDSPEC, GIT_EEXISTS or an error code
|
||||
*
|
||||
*/
|
||||
@ -275,7 +388,9 @@ GIT_EXTERN(int) git_reference_rename(
|
||||
git_reference **new_ref,
|
||||
git_reference *ref,
|
||||
const char *new_name,
|
||||
int force);
|
||||
int force,
|
||||
const git_signature *signature,
|
||||
const char *log_message);
|
||||
|
||||
/**
|
||||
* Delete an existing reference.
|
||||
@ -284,11 +399,25 @@ GIT_EXTERN(int) git_reference_rename(
|
||||
* will be immediately removed on disk but the memory will not be freed.
|
||||
* Callers must call `git_reference_free`.
|
||||
*
|
||||
* This function will return an error if the reference has changed
|
||||
* from the time it was looked up.
|
||||
*
|
||||
* @param ref The reference to remove
|
||||
* @return 0 or an error code
|
||||
* @return 0, GIT_EMODIFIED or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_delete(git_reference *ref);
|
||||
|
||||
/**
|
||||
* Delete an existing reference by name
|
||||
*
|
||||
* This method removes the named reference from the repository without
|
||||
* looking at its old value.
|
||||
*
|
||||
* @param name The reference to remove
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_remove(git_repository *repo, const char *name);
|
||||
|
||||
/**
|
||||
* Fill a list with all the references that can be found in a repository.
|
||||
*
|
||||
@ -310,20 +439,33 @@ typedef int (*git_reference_foreach_name_cb)(const char *name, void *payload);
|
||||
* Perform a callback on each reference in the repository.
|
||||
*
|
||||
* The `callback` function will be called for each reference in the
|
||||
* repository, receiving the name of the reference and the `payload` value
|
||||
* repository, receiving the reference object and the `payload` value
|
||||
* passed to this method. Returning a non-zero value from the callback
|
||||
* will terminate the iteration.
|
||||
*
|
||||
* @param repo Repository where to find the refs
|
||||
* @param callback Function which will be called for every listed ref
|
||||
* @param payload Additional data to pass to the callback
|
||||
* @return 0 on success, GIT_EUSER on non-zero callback, or error code
|
||||
* @return 0 on success, non-zero callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_foreach(
|
||||
git_repository *repo,
|
||||
git_reference_foreach_cb callback,
|
||||
void *payload);
|
||||
|
||||
/**
|
||||
* Perform a callback on the fully-qualified name of each reference.
|
||||
*
|
||||
* The `callback` function will be called for each reference in the
|
||||
* repository, receiving the name of the reference and the `payload` value
|
||||
* passed to this method. Returning a non-zero value from the callback
|
||||
* will terminate the iteration.
|
||||
*
|
||||
* @param repo Repository where to find the refs
|
||||
* @param callback Function which will be called for every listed ref name
|
||||
* @param payload Additional data to pass to the callback
|
||||
* @return 0 on success, non-zero callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_foreach_name(
|
||||
git_repository *repo,
|
||||
git_reference_foreach_name_cb callback,
|
||||
@ -343,7 +485,9 @@ GIT_EXTERN(void) git_reference_free(git_reference *ref);
|
||||
* @param ref2 The second git_reference
|
||||
* @return 0 if the same, else a stable but meaningless ordering.
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_cmp(git_reference *ref1, git_reference *ref2);
|
||||
GIT_EXTERN(int) git_reference_cmp(
|
||||
const git_reference *ref1,
|
||||
const git_reference *ref2);
|
||||
|
||||
/**
|
||||
* Create an iterator for the repo's references
|
||||
@ -379,6 +523,17 @@ GIT_EXTERN(int) git_reference_iterator_glob_new(
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_next(git_reference **out, git_reference_iterator *iter);
|
||||
|
||||
/**
|
||||
* Get the next reference's name
|
||||
*
|
||||
* This function is provided for convenience in case only the names
|
||||
* are interesting as it avoids the allocation of the `git_reference`
|
||||
* object which `git_reference_next()` needs.
|
||||
*
|
||||
* @param out pointer in which to store the string
|
||||
* @param iter the iterator
|
||||
* @return 0, GIT_ITEROVER if there are no more; or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_next_name(const char **out, git_reference_iterator *iter);
|
||||
|
||||
/**
|
||||
@ -415,12 +570,24 @@ GIT_EXTERN(int) git_reference_foreach_glob(
|
||||
/**
|
||||
* Check if a reflog exists for the specified reference.
|
||||
*
|
||||
* @param ref A git reference
|
||||
*
|
||||
* @param repo the repository
|
||||
* @param refname the reference's name
|
||||
* @return 0 when no reflog can be found, 1 when it exists;
|
||||
* otherwise an error code.
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_has_log(git_reference *ref);
|
||||
GIT_EXTERN(int) git_reference_has_log(git_repository *repo, const char *refname);
|
||||
|
||||
/**
|
||||
* Ensure there is a reflog for a particular reference.
|
||||
*
|
||||
* Make sure that successive updates to the reference will append to
|
||||
* its log.
|
||||
*
|
||||
* @param repo the repository
|
||||
* @param refname the reference's name
|
||||
* @return 0 or an error code.
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_ensure_log(git_repository *repo, const char *refname);
|
||||
|
||||
/**
|
||||
* Check if a reference is a local branch.
|
||||
@ -430,7 +597,7 @@ GIT_EXTERN(int) git_reference_has_log(git_reference *ref);
|
||||
* @return 1 when the reference lives in the refs/heads
|
||||
* namespace; 0 otherwise.
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_is_branch(git_reference *ref);
|
||||
GIT_EXTERN(int) git_reference_is_branch(const git_reference *ref);
|
||||
|
||||
/**
|
||||
* Check if a reference is a remote tracking branch
|
||||
@ -440,7 +607,7 @@ GIT_EXTERN(int) git_reference_is_branch(git_reference *ref);
|
||||
* @return 1 when the reference lives in the refs/remotes
|
||||
* namespace; 0 otherwise.
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_is_remote(git_reference *ref);
|
||||
GIT_EXTERN(int) git_reference_is_remote(const git_reference *ref);
|
||||
|
||||
/**
|
||||
* Check if a reference is a tag
|
||||
@ -450,7 +617,17 @@ GIT_EXTERN(int) git_reference_is_remote(git_reference *ref);
|
||||
* @return 1 when the reference lives in the refs/tags
|
||||
* namespace; 0 otherwise.
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_is_tag(git_reference *ref);
|
||||
GIT_EXTERN(int) git_reference_is_tag(const git_reference *ref);
|
||||
|
||||
/**
|
||||
* Check if a reference is a note
|
||||
*
|
||||
* @param ref A git reference
|
||||
*
|
||||
* @return 1 when the reference lives in the refs/notes
|
||||
* namespace; 0 otherwise.
|
||||
*/
|
||||
GIT_EXTERN(int) git_reference_is_note(const git_reference *ref);
|
||||
|
||||
typedef enum {
|
||||
GIT_REF_FORMAT_NORMAL = 0u,
|
||||
@ -490,7 +667,7 @@ typedef enum {
|
||||
* Once normalized, if the reference name is valid, it will be returned in
|
||||
* the user allocated buffer.
|
||||
*
|
||||
* See `git_reference_create_symbolic()` for rules about valid names.
|
||||
* See `git_reference_symbolic_create()` for rules about valid names.
|
||||
*
|
||||
* @param buffer_out User allocated buffer to store normalized name
|
||||
* @param buffer_size Size of buffer_out
|
||||
@ -554,7 +731,7 @@ GIT_EXTERN(int) git_reference_is_valid_name(const char *refname);
|
||||
* @param ref a reference
|
||||
* @return the human-readable version of the name
|
||||
*/
|
||||
GIT_EXTERN(const char *) git_reference_shorthand(git_reference *ref);
|
||||
GIT_EXTERN(const char *) git_reference_shorthand(const git_reference *ref);
|
||||
|
||||
|
||||
/** @} */
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "common.h"
|
||||
#include "types.h"
|
||||
#include "net.h"
|
||||
#include "buffer.h"
|
||||
|
||||
/**
|
||||
* @file git2/refspec.h
|
||||
@ -82,23 +83,21 @@ GIT_EXTERN(int) git_refspec_dst_matches(const git_refspec *refspec, const char *
|
||||
* Transform a reference to its target following the refspec's rules
|
||||
*
|
||||
* @param out where to store the target name
|
||||
* @param outlen the size of the `out` buffer
|
||||
* @param spec the refspec
|
||||
* @param name the name of the reference to transform
|
||||
* @return 0, GIT_EBUFS or another error
|
||||
*/
|
||||
GIT_EXTERN(int) git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, const char *name);
|
||||
GIT_EXTERN(int) git_refspec_transform(git_buf *out, const git_refspec *spec, const char *name);
|
||||
|
||||
/**
|
||||
* Transform a target reference to its source reference following the refspec's rules
|
||||
*
|
||||
* @param out where to store the source reference name
|
||||
* @param outlen the size of the `out` buffer
|
||||
* @param spec the refspec
|
||||
* @param name the name of the reference to transform
|
||||
* @return 0, GIT_EBUFS or another error
|
||||
*/
|
||||
GIT_EXTERN(int) git_refspec_rtransform(char *out, size_t outlen, const git_refspec *spec, const char *name);
|
||||
GIT_EXTERN(int) git_refspec_rtransform(git_buf *out, const git_refspec *spec, const char *name);
|
||||
|
||||
GIT_END_DECL
|
||||
|
||||
|
@ -62,10 +62,10 @@ GIT_EXTERN(int) git_remote_create_with_fetchspec(
|
||||
const char *fetch);
|
||||
|
||||
/**
|
||||
* Create a remote in memory
|
||||
* Create an anonymous remote
|
||||
*
|
||||
* Create a remote with the given refspec in memory. You can use
|
||||
* this when you have a URL instead of a remote's name. Note that in-memory
|
||||
* Create a remote with the given url and refspec in memory. You can use
|
||||
* this when you have a URL instead of a remote's name. Note that anonymous
|
||||
* remotes cannot be converted to persisted remotes.
|
||||
*
|
||||
* The name, when provided, will be checked for validity.
|
||||
@ -73,15 +73,15 @@ GIT_EXTERN(int) git_remote_create_with_fetchspec(
|
||||
*
|
||||
* @param out pointer to the new remote object
|
||||
* @param repo the associated repository
|
||||
* @param fetch the fetch refspec to use for this remote.
|
||||
* @param url the remote repository's URL
|
||||
* @param fetch the fetch refspec to use for this remote.
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_create_inmemory(
|
||||
GIT_EXTERN(int) git_remote_create_anonymous(
|
||||
git_remote **out,
|
||||
git_repository *repo,
|
||||
const char *fetch,
|
||||
const char *url);
|
||||
const char *url,
|
||||
const char *fetch);
|
||||
|
||||
/**
|
||||
* Get the information for a particular remote
|
||||
@ -107,6 +107,18 @@ GIT_EXTERN(int) git_remote_load(git_remote **out, git_repository *repo, const ch
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_save(const git_remote *remote);
|
||||
|
||||
/**
|
||||
* Create a copy of an existing remote. All internal strings are also
|
||||
* duplicated. Callbacks are not duplicated.
|
||||
*
|
||||
* Call `git_remote_free` to free the data.
|
||||
*
|
||||
* @param dest pointer where to store the copy
|
||||
* @param source object to copy
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_dup(git_remote **dest, git_remote *source);
|
||||
|
||||
/**
|
||||
* Get the remote's repository
|
||||
*
|
||||
@ -182,7 +194,7 @@ GIT_EXTERN(int) git_remote_add_fetch(git_remote *remote, const char *refspec);
|
||||
* @param array pointer to the array in which to store the strings
|
||||
* @param remote the remote to query
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_get_fetch_refspecs(git_strarray *array, git_remote *remote);
|
||||
GIT_EXTERN(int) git_remote_get_fetch_refspecs(git_strarray *array, const git_remote *remote);
|
||||
|
||||
/**
|
||||
* Set the remote's list of fetch refspecs
|
||||
@ -215,7 +227,7 @@ GIT_EXTERN(int) git_remote_add_push(git_remote *remote, const char *refspec);
|
||||
* @param array pointer to the array in which to store the strings
|
||||
* @param remote the remote to query
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_get_push_refspecs(git_strarray *array, git_remote *remote);
|
||||
GIT_EXTERN(int) git_remote_get_push_refspecs(git_strarray *array, const git_remote *remote);
|
||||
|
||||
/**
|
||||
* Set the remote's list of push refspecs
|
||||
@ -242,7 +254,7 @@ GIT_EXTERN(void) git_remote_clear_refspecs(git_remote *remote);
|
||||
* @param remote the remote
|
||||
* @return the amount of refspecs configured in this remote
|
||||
*/
|
||||
GIT_EXTERN(size_t) git_remote_refspec_count(git_remote *remote);
|
||||
GIT_EXTERN(size_t) git_remote_refspec_count(const git_remote *remote);
|
||||
|
||||
/**
|
||||
* Get a refspec from the remote
|
||||
@ -251,7 +263,7 @@ GIT_EXTERN(size_t) git_remote_refspec_count(git_remote *remote);
|
||||
* @param n the refspec to get
|
||||
* @return the nth refspec
|
||||
*/
|
||||
GIT_EXTERN(const git_refspec *)git_remote_get_refspec(git_remote *remote, size_t n);
|
||||
GIT_EXTERN(const git_refspec *)git_remote_get_refspec(const git_remote *remote, size_t n);
|
||||
|
||||
/**
|
||||
* Open a connection to a remote
|
||||
@ -307,7 +319,7 @@ GIT_EXTERN(int) git_remote_download(git_remote *remote);
|
||||
* @param remote the remote
|
||||
* @return 1 if it's connected, 0 otherwise.
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_connected(git_remote *remote);
|
||||
GIT_EXTERN(int) git_remote_connected(const git_remote *remote);
|
||||
|
||||
/**
|
||||
* Cancel the operation
|
||||
@ -343,9 +355,16 @@ GIT_EXTERN(void) git_remote_free(git_remote *remote);
|
||||
* Update the tips to the new state
|
||||
*
|
||||
* @param remote the remote to update
|
||||
* @param signature The identity to use when updating reflogs
|
||||
* @param reflog_message The message to insert into the reflogs. If NULL, the
|
||||
* default is "fetch <name>", where <name> is the name of
|
||||
* the remote (or its url, for in-memory remotes).
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_update_tips(git_remote *remote);
|
||||
GIT_EXTERN(int) git_remote_update_tips(
|
||||
git_remote *remote,
|
||||
const git_signature *signature,
|
||||
const char *reflog_message);
|
||||
|
||||
/**
|
||||
* Download new data and update tips
|
||||
@ -354,9 +373,15 @@ GIT_EXTERN(int) git_remote_update_tips(git_remote *remote);
|
||||
* disconnect and update the remote-tracking branches.
|
||||
*
|
||||
* @param remote the remote to fetch from
|
||||
* @param signature The identity to use when updating reflogs
|
||||
* @param reflog_message The message to insert into the reflogs. If NULL, the
|
||||
* default is "fetch"
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_fetch(git_remote *remote);
|
||||
GIT_EXTERN(int) git_remote_fetch(
|
||||
git_remote *remote,
|
||||
const git_signature *signature,
|
||||
const char *reflog_message);
|
||||
|
||||
/**
|
||||
* Return whether a string is a valid remote URL
|
||||
@ -432,7 +457,7 @@ struct git_remote_callbacks {
|
||||
* progress side-band will be passed to this function (this is
|
||||
* the 'counting objects' output.
|
||||
*/
|
||||
int (*progress)(const char *str, int len, void *data);
|
||||
git_transport_message_cb sideband_progress;
|
||||
|
||||
/**
|
||||
* Completion is called when different parts of the download
|
||||
@ -443,15 +468,18 @@ struct git_remote_callbacks {
|
||||
/**
|
||||
* This will be called if the remote host requires
|
||||
* authentication in order to connect to it.
|
||||
*
|
||||
* Returning GIT_PASSTHROUGH will make libgit2 behave as
|
||||
* though this field isn't set.
|
||||
*/
|
||||
int (*credentials)(git_cred **cred, const char *url, const char *username_from_url, unsigned int allowed_types, void *data);
|
||||
git_cred_acquire_cb credentials;
|
||||
|
||||
/**
|
||||
* During the download of new data, this will be regularly
|
||||
* called with the current count of progress done by the
|
||||
* indexer.
|
||||
*/
|
||||
int (*transfer_progress)(const git_transfer_progress *stats, void *data);
|
||||
git_transfer_progress_cb transfer_progress;
|
||||
|
||||
/**
|
||||
* Each time a reference is updated locally, this function
|
||||
@ -469,6 +497,18 @@ struct git_remote_callbacks {
|
||||
#define GIT_REMOTE_CALLBACKS_VERSION 1
|
||||
#define GIT_REMOTE_CALLBACKS_INIT {GIT_REMOTE_CALLBACKS_VERSION}
|
||||
|
||||
/**
|
||||
* Initializes a `git_remote_callbacks` with default values. Equivalent to
|
||||
* creating an instance with GIT_REMOTE_CALLBACKS_INIT.
|
||||
*
|
||||
* @param opts the `git_remote_callbacks` struct to initialize
|
||||
* @param version Version of struct; pass `GIT_REMOTE_CALLBACKS_VERSION`
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_init_callbacks(
|
||||
git_remote_callbacks *opts,
|
||||
unsigned int version);
|
||||
|
||||
/**
|
||||
* Set the callbacks for a remote
|
||||
*
|
||||
@ -481,6 +521,17 @@ struct git_remote_callbacks {
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_set_callbacks(git_remote *remote, const git_remote_callbacks *callbacks);
|
||||
|
||||
/**
|
||||
* Retrieve the current callback structure
|
||||
*
|
||||
* This provides read access to the callbacks structure as the remote
|
||||
* sees it.
|
||||
*
|
||||
* @param remote the remote to query
|
||||
* @return a pointer to the callbacks structure
|
||||
*/
|
||||
GIT_EXTERN(const git_remote_callbacks *) git_remote_get_callbacks(git_remote *remote);
|
||||
|
||||
/**
|
||||
* Get the statistics structure that is filled in by the fetch operation.
|
||||
*/
|
||||
@ -498,7 +549,7 @@ typedef enum {
|
||||
* @param remote the remote to query
|
||||
* @return the auto-follow setting
|
||||
*/
|
||||
GIT_EXTERN(git_remote_autotag_option_t) git_remote_autotag(git_remote *remote);
|
||||
GIT_EXTERN(git_remote_autotag_option_t) git_remote_autotag(const git_remote *remote);
|
||||
|
||||
/**
|
||||
* Set the tag auto-follow setting
|
||||
@ -521,18 +572,17 @@ GIT_EXTERN(void) git_remote_set_autotag(
|
||||
*
|
||||
* A temporary in-memory remote cannot be given a name with this method.
|
||||
*
|
||||
* @param problems non-default refspecs cannot be renamed and will be
|
||||
* stored here for further processing by the caller. Always free this
|
||||
* strarray on succesful return.
|
||||
* @param remote the remote to rename
|
||||
* @param new_name the new name the remote should bear
|
||||
* @param callback Optional callback to notify the consumer of fetch refspecs
|
||||
* that haven't been automatically updated and need potential manual tweaking.
|
||||
* @param payload Additional data to pass to the callback
|
||||
* @return 0, GIT_EINVALIDSPEC, GIT_EEXISTS or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_rename(
|
||||
git_strarray *problems,
|
||||
git_remote *remote,
|
||||
const char *new_name,
|
||||
git_remote_rename_problem_cb callback,
|
||||
void *payload);
|
||||
const char *new_name);
|
||||
|
||||
/**
|
||||
* Retrieve the update FETCH_HEAD setting.
|
||||
@ -559,6 +609,35 @@ GIT_EXTERN(void) git_remote_set_update_fetchhead(git_remote *remote, int value);
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_is_valid_name(const char *remote_name);
|
||||
|
||||
/**
|
||||
* Delete an existing persisted remote.
|
||||
*
|
||||
* All remote-tracking branches and configuration settings
|
||||
* for the remote will be removed.
|
||||
*
|
||||
* @param remote A valid remote
|
||||
* @return 0 on success, or an error code.
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_delete(git_remote *remote);
|
||||
|
||||
/**
|
||||
* Retrieve the name of the remote's default branch
|
||||
*
|
||||
* The default branch of a repository is the branch which HEAD points
|
||||
* to. If the remote does not support reporting this information
|
||||
* directly, it performs the guess as git does; that is, if there are
|
||||
* multiple branches which point to the same commit, the first one is
|
||||
* chosen. If the master branch is a candidate, it wins.
|
||||
*
|
||||
* This function must only be called after connecting.
|
||||
*
|
||||
* @param out the buffern in which to store the reference name
|
||||
* @param remote the remote
|
||||
* @return 0, GIT_ENOTFOUND if the remote does not have any references
|
||||
* or none of them point to HEAD's commit, or an error message.
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_default_branch(git_buf *out, git_remote *remote);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
#endif
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "common.h"
|
||||
#include "types.h"
|
||||
#include "oid.h"
|
||||
#include "buffer.h"
|
||||
|
||||
/**
|
||||
* @file git2/repository.h
|
||||
@ -58,10 +59,8 @@ GIT_EXTERN(int) git_repository_wrap_odb(git_repository **out, git_odb *odb);
|
||||
* The method will automatically detect if the repository is bare
|
||||
* (if there is a repository).
|
||||
*
|
||||
* @param path_out The user allocated buffer which will
|
||||
* contain the found path.
|
||||
*
|
||||
* @param path_size repository_path size
|
||||
* @param out A pointer to a user-allocated git_buf which will contain
|
||||
* the found path.
|
||||
*
|
||||
* @param start_path The base path where the lookup starts.
|
||||
*
|
||||
@ -77,8 +76,7 @@ GIT_EXTERN(int) git_repository_wrap_odb(git_repository **out, git_odb *odb);
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_repository_discover(
|
||||
char *path_out,
|
||||
size_t path_size,
|
||||
git_buf *out,
|
||||
const char *start_path,
|
||||
int across_fs,
|
||||
const char *ceiling_dirs);
|
||||
@ -269,6 +267,18 @@ typedef struct {
|
||||
#define GIT_REPOSITORY_INIT_OPTIONS_VERSION 1
|
||||
#define GIT_REPOSITORY_INIT_OPTIONS_INIT {GIT_REPOSITORY_INIT_OPTIONS_VERSION}
|
||||
|
||||
/**
|
||||
* Initializes a `git_repository_init_options` with default values. Equivalent
|
||||
* to creating an instance with GIT_REPOSITORY_INIT_OPTIONS_INIT.
|
||||
*
|
||||
* @param opts the `git_repository_init_options` struct to initialize
|
||||
* @param version Version of struct; pass `GIT_REPOSITORY_INIT_OPTIONS_VERSION`
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_repository_init_init_options(
|
||||
git_repository_init_options *opts,
|
||||
unsigned int version);
|
||||
|
||||
/**
|
||||
* Create a new Git repository in the given folder with extended controls.
|
||||
*
|
||||
@ -398,12 +408,28 @@ GIT_EXTERN(int) git_repository_is_bare(git_repository *repo);
|
||||
* The configuration file must be freed once it's no longer
|
||||
* being used by the user.
|
||||
*
|
||||
* @param out Pointer to store the loaded config file
|
||||
* @param out Pointer to store the loaded configuration
|
||||
* @param repo A repository object
|
||||
* @return 0, or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_repository_config(git_config **out, git_repository *repo);
|
||||
|
||||
/**
|
||||
* Get a snapshot of the repository's configuration
|
||||
*
|
||||
* Convenience function to take a snapshot from the repository's
|
||||
* configuration. The contents of this snapshot will not change,
|
||||
* even if the underlying config files are modified.
|
||||
*
|
||||
* The configuration file must be freed once it's no longer
|
||||
* being used by the user.
|
||||
*
|
||||
* @param out Pointer to store the loaded configuration
|
||||
* @param repo the repository
|
||||
* @return 0, or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_repository_config_snapshot(git_config **out, git_repository *repo);
|
||||
|
||||
/**
|
||||
* Get the Object Database for this repository.
|
||||
*
|
||||
@ -464,21 +490,11 @@ GIT_EXTERN(int) git_repository_index(git_index **out, git_repository *repo);
|
||||
* Use this function to get the contents of this file. Don't forget to
|
||||
* remove the file after you create the commit.
|
||||
*
|
||||
* If the repository message exists and there are no errors reading it, this
|
||||
* returns the bytes needed to store the message in memory (i.e. message
|
||||
* file size plus one terminating NUL byte). That value is returned even if
|
||||
* `out` is NULL or `len` is shorter than the necessary size.
|
||||
*
|
||||
* The `out` buffer will *always* be NUL terminated, even if truncation
|
||||
* occurs.
|
||||
*
|
||||
* @param out Buffer to write data into or NULL to just read required size
|
||||
* @param len Length of `out` buffer in bytes
|
||||
* @param out git_buf to write data into
|
||||
* @param repo Repository to read prepared message from
|
||||
* @return GIT_ENOTFOUND if no message exists, other value < 0 for other
|
||||
* errors, or total bytes in message (may be > `len`) on success
|
||||
* @return 0, GIT_ENOTFOUND if no message exists or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_repository_message(char *out, size_t len, git_repository *repo);
|
||||
GIT_EXTERN(int) git_repository_message(git_buf *out, git_repository *repo);
|
||||
|
||||
/**
|
||||
* Remove git's prepared message.
|
||||
@ -488,13 +504,13 @@ GIT_EXTERN(int) git_repository_message(char *out, size_t len, git_repository *re
|
||||
GIT_EXTERN(int) git_repository_message_remove(git_repository *repo);
|
||||
|
||||
/**
|
||||
* Remove all the metadata associated with an ongoing git merge, including
|
||||
* MERGE_HEAD, MERGE_MSG, etc.
|
||||
* Remove all the metadata associated with an ongoing command like merge,
|
||||
* revert, cherry-pick, etc. For example: MERGE_HEAD, MERGE_MSG, etc.
|
||||
*
|
||||
* @param repo A repository object
|
||||
* @return 0 on success, or error
|
||||
*/
|
||||
GIT_EXTERN(int) git_repository_merge_cleanup(git_repository *repo);
|
||||
GIT_EXTERN(int) git_repository_state_cleanup(git_repository *repo);
|
||||
|
||||
typedef int (*git_repository_fetchhead_foreach_cb)(const char *ref_name,
|
||||
const char *remote_url,
|
||||
@ -503,14 +519,18 @@ typedef int (*git_repository_fetchhead_foreach_cb)(const char *ref_name,
|
||||
void *payload);
|
||||
|
||||
/**
|
||||
* Call callback 'callback' for each entry in the given FETCH_HEAD file.
|
||||
* Invoke 'callback' for each entry in the given FETCH_HEAD file.
|
||||
*
|
||||
* Return a non-zero value from the callback to stop the loop.
|
||||
*
|
||||
* @param repo A repository object
|
||||
* @param callback Callback function
|
||||
* @param payload Pointer to callback data (optional)
|
||||
* @return 0 on success, GIT_ENOTFOUND, GIT_EUSER or error
|
||||
* @return 0 on success, non-zero callback return value, GIT_ENOTFOUND if
|
||||
* there is no FETCH_HEAD file, or other error code.
|
||||
*/
|
||||
GIT_EXTERN(int) git_repository_fetchhead_foreach(git_repository *repo,
|
||||
GIT_EXTERN(int) git_repository_fetchhead_foreach(
|
||||
git_repository *repo,
|
||||
git_repository_fetchhead_foreach_cb callback,
|
||||
void *payload);
|
||||
|
||||
@ -518,15 +538,19 @@ typedef int (*git_repository_mergehead_foreach_cb)(const git_oid *oid,
|
||||
void *payload);
|
||||
|
||||
/**
|
||||
* If a merge is in progress, call callback 'cb' for each commit ID in the
|
||||
* If a merge is in progress, invoke 'callback' for each commit ID in the
|
||||
* MERGE_HEAD file.
|
||||
*
|
||||
* Return a non-zero value from the callback to stop the loop.
|
||||
*
|
||||
* @param repo A repository object
|
||||
* @param callback Callback function
|
||||
* @param payload Pointer to callback data (optional)
|
||||
* @return 0 on success, GIT_ENOTFOUND, GIT_EUSER or error
|
||||
* @return 0 on success, non-zero callback return value, GIT_ENOTFOUND if
|
||||
* there is no MERGE_HEAD file, or other error code.
|
||||
*/
|
||||
GIT_EXTERN(int) git_repository_mergehead_foreach(git_repository *repo,
|
||||
GIT_EXTERN(int) git_repository_mergehead_foreach(
|
||||
git_repository *repo,
|
||||
git_repository_mergehead_foreach_cb callback,
|
||||
void *payload);
|
||||
|
||||
@ -538,6 +562,10 @@ GIT_EXTERN(int) git_repository_mergehead_foreach(git_repository *repo,
|
||||
* hash a file in the repository and you want to apply filtering rules (e.g.
|
||||
* crlf filters) before generating the SHA, then use this function.
|
||||
*
|
||||
* Note: if the repository has `core.safecrlf` set to fail and the
|
||||
* filtering triggers that failure, then this function will return an
|
||||
* error and not calculate the hash of the file.
|
||||
*
|
||||
* @param out Output value of calculated SHA
|
||||
* @param repo Repository pointer
|
||||
* @param path Path to file on disk whose contents should be hashed. If the
|
||||
@ -547,6 +575,7 @@ GIT_EXTERN(int) git_repository_mergehead_foreach(git_repository *repo,
|
||||
* NULL, then the `path` parameter will be used instead. If
|
||||
* this is passed as the empty string, then no filters will be
|
||||
* applied when calculating the hash.
|
||||
* @return 0 on success, or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_repository_hashfile(
|
||||
git_oid *out,
|
||||
@ -571,11 +600,15 @@ GIT_EXTERN(int) git_repository_hashfile(
|
||||
*
|
||||
* @param repo Repository pointer
|
||||
* @param refname Canonical name of the reference the HEAD should point at
|
||||
* @param signature The identity that will used to populate the reflog entry
|
||||
* @param log_message The one line long message to be appended to the reflog
|
||||
* @return 0 on success, or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_repository_set_head(
|
||||
git_repository* repo,
|
||||
const char* refname);
|
||||
const char* refname,
|
||||
const git_signature *signature,
|
||||
const char *log_message);
|
||||
|
||||
/**
|
||||
* Make the repository HEAD directly point to the Commit.
|
||||
@ -591,11 +624,15 @@ GIT_EXTERN(int) git_repository_set_head(
|
||||
*
|
||||
* @param repo Repository pointer
|
||||
* @param commitish Object id of the Commit the HEAD should point to
|
||||
* @param signature The identity that will used to populate the reflog entry
|
||||
* @param log_message The one line long message to be appended to the reflog
|
||||
* @return 0 on success, or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_repository_set_head_detached(
|
||||
git_repository* repo,
|
||||
const git_oid* commitish);
|
||||
const git_oid* commitish,
|
||||
const git_signature *signature,
|
||||
const char *log_message);
|
||||
|
||||
/**
|
||||
* Detach the HEAD.
|
||||
@ -611,11 +648,15 @@ GIT_EXTERN(int) git_repository_set_head_detached(
|
||||
* Otherwise, the HEAD will be detached and point to the peeled Commit.
|
||||
*
|
||||
* @param repo Repository pointer
|
||||
* @param signature The identity that will used to populate the reflog entry
|
||||
* @param reflog_message The one line long message to be appended to the reflog
|
||||
* @return 0 on success, GIT_EUNBORNBRANCH when HEAD points to a non existing
|
||||
* branch or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_repository_detach_head(
|
||||
git_repository* repo);
|
||||
git_repository* repo,
|
||||
const git_signature *signature,
|
||||
const char *reflog_message);
|
||||
|
||||
typedef enum {
|
||||
GIT_REPOSITORY_STATE_NONE,
|
||||
|
@ -19,9 +19,9 @@ GIT_BEGIN_DECL
|
||||
* Kinds of reset operation
|
||||
*/
|
||||
typedef enum {
|
||||
GIT_RESET_SOFT = 1, /** Move the head to the given commit */
|
||||
GIT_RESET_MIXED = 2, /** SOFT plus reset index to the commit */
|
||||
GIT_RESET_HARD = 3, /** MIXED plus changes in working tree discarded */
|
||||
GIT_RESET_SOFT = 1, /**< Move the head to the given commit */
|
||||
GIT_RESET_MIXED = 2, /**< SOFT plus reset index to the commit */
|
||||
GIT_RESET_HARD = 3, /**< MIXED plus changes in working tree discarded */
|
||||
} git_reset_t;
|
||||
|
||||
/**
|
||||
@ -48,10 +48,21 @@ typedef enum {
|
||||
*
|
||||
* @param reset_type Kind of reset operation to perform.
|
||||
*
|
||||
* @param signature The identity that will used to populate the reflog entry
|
||||
*
|
||||
* @param log_message The one line long message to be appended to the reflog.
|
||||
* The reflog is only updated if the affected direct reference is actually
|
||||
* changing. If NULL, the default is "reset: moving"; if you want something more
|
||||
* useful, provide a message.
|
||||
*
|
||||
* @return 0 on success or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_reset(
|
||||
git_repository *repo, git_object *target, git_reset_t reset_type);
|
||||
git_repository *repo,
|
||||
git_object *target,
|
||||
git_reset_t reset_type,
|
||||
git_signature *signature,
|
||||
const char *log_message);
|
||||
|
||||
/**
|
||||
* Updates some entries in the index from the target commit tree.
|
||||
|
86
include/git2/revert.h
Normal file
86
include/git2/revert.h
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) the libgit2 contributors. All rights reserved.
|
||||
*
|
||||
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
||||
* a Linking Exception. For full terms see the included COPYING file.
|
||||
*/
|
||||
#ifndef INCLUDE_git_revert_h__
|
||||
#define INCLUDE_git_revert_h__
|
||||
|
||||
#include "common.h"
|
||||
#include "types.h"
|
||||
#include "merge.h"
|
||||
|
||||
/**
|
||||
* @file git2/revert.h
|
||||
* @brief Git revert routines
|
||||
* @defgroup git_revert Git revert routines
|
||||
* @ingroup Git
|
||||
* @{
|
||||
*/
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
|
||||
/** For merge commits, the "mainline" is treated as the parent. */
|
||||
unsigned int mainline;
|
||||
|
||||
git_merge_options merge_opts;
|
||||
git_checkout_options checkout_opts;
|
||||
} git_revert_options;
|
||||
|
||||
#define GIT_REVERT_OPTIONS_VERSION 1
|
||||
#define GIT_REVERT_OPTIONS_INIT {GIT_REVERT_OPTIONS_VERSION, 0, GIT_MERGE_OPTIONS_INIT, GIT_CHECKOUT_OPTIONS_INIT}
|
||||
|
||||
/**
|
||||
* Initializes a `git_revert_options` with default values. Equivalent to
|
||||
* creating an instance with GIT_REVERT_OPTIONS_INIT.
|
||||
*
|
||||
* @param opts the `git_revert_options` struct to initialize
|
||||
* @param version Version of struct; pass `GIT_REVERT_OPTIONS_VERSION`
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_revert_init_options(
|
||||
git_revert_options *opts,
|
||||
unsigned int version);
|
||||
|
||||
/**
|
||||
* Reverts the given commit against the given "our" commit, producing an
|
||||
* index that reflects the result of the revert.
|
||||
*
|
||||
* The returned index must be freed explicitly with `git_index_free`.
|
||||
*
|
||||
* @param out pointer to store the index result in
|
||||
* @param repo the repository that contains the given commits
|
||||
* @param revert_commit the commit to revert
|
||||
* @param our_commit the commit to revert against (eg, HEAD)
|
||||
* @param mainline the parent of the revert commit, if it is a merge
|
||||
* @param merge_options the merge options (or null for defaults)
|
||||
* @return zero on success, -1 on failure.
|
||||
*/
|
||||
int git_revert_commit(
|
||||
git_index **out,
|
||||
git_repository *repo,
|
||||
git_commit *revert_commit,
|
||||
git_commit *our_commit,
|
||||
unsigned int mainline,
|
||||
const git_merge_options *merge_options);
|
||||
|
||||
/**
|
||||
* Reverts the given commit, producing changes in the working directory.
|
||||
*
|
||||
* @param repo the repository to revert
|
||||
* @param commit the commit to revert
|
||||
* @param given_opts merge flags
|
||||
* @return zero on success, -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_revert(
|
||||
git_repository *repo,
|
||||
git_commit *commit,
|
||||
const git_revert_options *given_opts);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
#endif
|
||||
|
@ -87,7 +87,7 @@ GIT_EXTERN(void) git_revwalk_reset(git_revwalk *walker);
|
||||
/**
|
||||
* Mark a commit to start traversal from.
|
||||
*
|
||||
* The given OID must belong to a commit on the walked
|
||||
* The given OID must belong to a committish on the walked
|
||||
* repository.
|
||||
*
|
||||
* The given commit will be used as one of the roots
|
||||
@ -108,7 +108,10 @@ GIT_EXTERN(int) git_revwalk_push(git_revwalk *walk, const git_oid *id);
|
||||
* pattern will be pushed to the revision walker.
|
||||
*
|
||||
* A leading 'refs/' is implied if not present as well as a trailing
|
||||
* '/ *' if the glob lacks '?', '*' or '['.
|
||||
* '/\*' if the glob lacks '?', '\*' or '['.
|
||||
*
|
||||
* Any references matching this glob which do not point to a
|
||||
* committish will be ignored.
|
||||
*
|
||||
* @param walk the walker being used for the traversal
|
||||
* @param glob the glob pattern references should match
|
||||
@ -127,7 +130,7 @@ GIT_EXTERN(int) git_revwalk_push_head(git_revwalk *walk);
|
||||
/**
|
||||
* Mark a commit (and its ancestors) uninteresting for the output.
|
||||
*
|
||||
* The given OID must belong to a commit on the walked
|
||||
* The given OID must belong to a committish on the walked
|
||||
* repository.
|
||||
*
|
||||
* The resolved commit and all its parents will be hidden from the
|
||||
@ -147,7 +150,10 @@ GIT_EXTERN(int) git_revwalk_hide(git_revwalk *walk, const git_oid *commit_id);
|
||||
* revision walk.
|
||||
*
|
||||
* A leading 'refs/' is implied if not present as well as a trailing
|
||||
* '/ *' if the glob lacks '?', '*' or '['.
|
||||
* '/\*' if the glob lacks '?', '\*' or '['.
|
||||
*
|
||||
* Any references matching this glob which do not point to a
|
||||
* committish will be ignored.
|
||||
*
|
||||
* @param walk the walker being used for the traversal
|
||||
* @param glob the glob pattern references should match
|
||||
@ -166,7 +172,7 @@ GIT_EXTERN(int) git_revwalk_hide_head(git_revwalk *walk);
|
||||
/**
|
||||
* Push the OID pointed to by a reference
|
||||
*
|
||||
* The reference must point to a commit.
|
||||
* The reference must point to a committish.
|
||||
*
|
||||
* @param walk the walker being used for the traversal
|
||||
* @param refname the reference to push
|
||||
@ -177,7 +183,7 @@ GIT_EXTERN(int) git_revwalk_push_ref(git_revwalk *walk, const char *refname);
|
||||
/**
|
||||
* Hide the OID pointed to by a reference
|
||||
*
|
||||
* The reference must point to a commit.
|
||||
* The reference must point to a committish.
|
||||
*
|
||||
* @param walk the walker being used for the traversal
|
||||
* @param refname the reference to hide
|
||||
@ -255,6 +261,30 @@ GIT_EXTERN(void) git_revwalk_free(git_revwalk *walk);
|
||||
*/
|
||||
GIT_EXTERN(git_repository *) git_revwalk_repository(git_revwalk *walk);
|
||||
|
||||
/**
|
||||
* This is a callback function that user can provide to hide a
|
||||
* commit and its parents. If the callback function returns non-zero value,
|
||||
* then this commit and its parents will be hidden.
|
||||
*
|
||||
* @param commit_id oid of Commit
|
||||
* @param payload User-specified pointer to data to be passed as data payload
|
||||
*/
|
||||
typedef int(*git_revwalk_hide_cb)(
|
||||
const git_oid *commit_id,
|
||||
void *payload);
|
||||
|
||||
/**
|
||||
* Adds a callback function to hide a commit and its parents
|
||||
*
|
||||
* @param walk the revision walker
|
||||
* @param hide_cb callback function to hide a commit and its parents
|
||||
* @param payload data payload to be passed to callback function
|
||||
*/
|
||||
GIT_EXTERN(int) git_revwalk_add_hide_cb(
|
||||
git_revwalk *walk,
|
||||
git_revwalk_hide_cb hide_cb,
|
||||
void *payload);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
#endif
|
||||
|
@ -68,10 +68,11 @@ GIT_EXTERN(int) git_signature_default(git_signature **out, git_repository *repo)
|
||||
*
|
||||
* Call `git_signature_free()` to free the data.
|
||||
*
|
||||
* @param sig signature to duplicated
|
||||
* @return a copy of sig, NULL on out of memory
|
||||
* @param dest pointer where to store the copy
|
||||
* @param sig signature to duplicate
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(git_signature *) git_signature_dup(const git_signature *sig);
|
||||
GIT_EXTERN(int) git_signature_dup(git_signature **dest, const git_signature *sig);
|
||||
|
||||
/**
|
||||
* Free an existing signature.
|
||||
|
@ -62,19 +62,15 @@ GIT_EXTERN(int) git_stash_save(
|
||||
unsigned int flags);
|
||||
|
||||
/**
|
||||
* When iterating over all the stashed states, callback that will be
|
||||
* issued per entry.
|
||||
* This is a callback function you can provide to iterate over all the
|
||||
* stashed states that will be invoked per entry.
|
||||
*
|
||||
* @param index The position within the stash list. 0 points to the
|
||||
* most recent stashed state.
|
||||
*
|
||||
* most recent stashed state.
|
||||
* @param message The stash message.
|
||||
*
|
||||
* @param stash_id The commit oid of the stashed state.
|
||||
*
|
||||
* @param payload Extra parameter to callback function.
|
||||
*
|
||||
* @return 0 on success, GIT_EUSER on non-zero callback, or error code
|
||||
* @return 0 to continue iterating or non-zero to stop
|
||||
*/
|
||||
typedef int (*git_stash_cb)(
|
||||
size_t index,
|
||||
@ -89,12 +85,12 @@ typedef int (*git_stash_cb)(
|
||||
*
|
||||
* @param repo Repository where to find the stash.
|
||||
*
|
||||
* @param callback Callback to invoke per found stashed state. The most recent
|
||||
* stash state will be enumerated first.
|
||||
* @param callback Callback to invoke per found stashed state. The most
|
||||
* recent stash state will be enumerated first.
|
||||
*
|
||||
* @param payload Extra parameter to callback function.
|
||||
*
|
||||
* @return 0 on success, GIT_EUSER on non-zero callback, or error code
|
||||
* @return 0 on success, non-zero callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_stash_foreach(
|
||||
git_repository *repo,
|
||||
|
@ -121,6 +121,11 @@ typedef enum {
|
||||
* - GIT_STATUS_OPT_NO_REFRESH bypasses the default status behavior of
|
||||
* doing a "soft" index reload (i.e. reloading the index data if the
|
||||
* file on disk has been modified outside libgit2).
|
||||
* - GIT_STATUS_OPT_UPDATE_INDEX tells libgit2 to refresh the stat cache
|
||||
* in the index for files that are unchanged but have out of date stat
|
||||
* information in the index. It will result in less work being done on
|
||||
* subsequent calls to get status. This is mutually exclusive with the
|
||||
* NO_REFRESH option.
|
||||
*
|
||||
* Calling `git_status_foreach()` is like calling the extended version
|
||||
* with: GIT_STATUS_OPT_INCLUDE_IGNORED, GIT_STATUS_OPT_INCLUDE_UNTRACKED,
|
||||
@ -141,6 +146,7 @@ typedef enum {
|
||||
GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY = (1u << 10),
|
||||
GIT_STATUS_OPT_RENAMES_FROM_REWRITES = (1u << 11),
|
||||
GIT_STATUS_OPT_NO_REFRESH = (1u << 12),
|
||||
GIT_STATUS_OPT_UPDATE_INDEX = (1u << 13),
|
||||
} git_status_opt_t;
|
||||
|
||||
#define GIT_STATUS_OPT_DEFAULTS \
|
||||
@ -174,6 +180,18 @@ typedef struct {
|
||||
#define GIT_STATUS_OPTIONS_VERSION 1
|
||||
#define GIT_STATUS_OPTIONS_INIT {GIT_STATUS_OPTIONS_VERSION}
|
||||
|
||||
/**
|
||||
* Initializes a `git_status_options` with default values. Equivalent to
|
||||
* creating an instance with GIT_STATUS_OPTIONS_INIT.
|
||||
*
|
||||
* @param opts The `git_status_options` instance to initialize.
|
||||
* @param version Version of struct; pass `GIT_STATUS_OPTIONS_VERSION`
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_status_init_options(
|
||||
git_status_options *opts,
|
||||
unsigned int version);
|
||||
|
||||
/**
|
||||
* A status entry, providing the differences between the file as it exists
|
||||
* in HEAD and the index, and providing the differences between the index
|
||||
@ -203,12 +221,12 @@ typedef struct {
|
||||
* into this function.
|
||||
*
|
||||
* If the callback returns a non-zero value, this function will stop looping
|
||||
* and return GIT_EUSER.
|
||||
* and return that value to caller.
|
||||
*
|
||||
* @param repo A repository object
|
||||
* @param callback The function to call on each file
|
||||
* @param payload Pointer to pass through to callback function
|
||||
* @return 0 on success, GIT_EUSER on non-zero callback, or error code
|
||||
* @return 0 on success, non-zero callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_status_foreach(
|
||||
git_repository *repo,
|
||||
@ -223,11 +241,16 @@ GIT_EXTERN(int) git_status_foreach(
|
||||
* in what order. See the `git_status_options` structure for details
|
||||
* about the additional controls that this makes available.
|
||||
*
|
||||
* Note that if a `pathspec` is given in the `git_status_options` to filter
|
||||
* the status, then the results from rename detection (if you enable it) may
|
||||
* not be accurate. To do rename detection properly, this must be called
|
||||
* with no `pathspec` so that all files can be considered.
|
||||
*
|
||||
* @param repo Repository object
|
||||
* @param opts Status options structure
|
||||
* @param callback The function to call on each file
|
||||
* @param payload Pointer to pass through to callback function
|
||||
* @return 0 on success, GIT_EUSER on non-zero callback, or error code
|
||||
* @return 0 on success, non-zero callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_status_foreach_ext(
|
||||
git_repository *repo,
|
||||
@ -238,8 +261,20 @@ GIT_EXTERN(int) git_status_foreach_ext(
|
||||
/**
|
||||
* Get file status for a single file.
|
||||
*
|
||||
* This is not quite the same as calling `git_status_foreach_ext()` with
|
||||
* the pathspec set to the specified path.
|
||||
* This tries to get status for the filename that you give. If no files
|
||||
* match that name (in either the HEAD, index, or working directory), this
|
||||
* returns GIT_ENOTFOUND.
|
||||
*
|
||||
* If the name matches multiple files (for example, if the `path` names a
|
||||
* directory or if running on a case- insensitive filesystem and yet the
|
||||
* HEAD has two entries that both match the path), then this returns
|
||||
* GIT_EAMBIGUOUS because it cannot give correct results.
|
||||
*
|
||||
* This does not do any sort of rename detection. Renames require a set of
|
||||
* targets and because of the path filtering, there is not enough
|
||||
* information to check renames correctly. To check file status with rename
|
||||
* detection, there is no choice but to do a full `git_status_list_new` and
|
||||
* scan through looking for the path that you are interested in.
|
||||
*
|
||||
* @param status_flags Output combination of git_status_t values for file
|
||||
* @param repo A repository object
|
||||
@ -256,6 +291,11 @@ GIT_EXTERN(int) git_status_file(
|
||||
/**
|
||||
* Gather file status information and populate the `git_status_list`.
|
||||
*
|
||||
* Note that if a `pathspec` is given in the `git_status_options` to filter
|
||||
* the status, then the results from rename detection (if you enable it) may
|
||||
* not be accurate. To do rename detection properly, this must be called
|
||||
* with no `pathspec` so that all files can be considered.
|
||||
*
|
||||
* @param out Pointer to store the status results in
|
||||
* @param repo Repository object
|
||||
* @param opts Status options structure
|
||||
@ -269,6 +309,9 @@ GIT_EXTERN(int) git_status_list_new(
|
||||
/**
|
||||
* Gets the count of status entries in this list.
|
||||
*
|
||||
* If there are no changes in status (at least according the options given
|
||||
* when the status list was created), this can return 0.
|
||||
*
|
||||
* @param statuslist Existing status list object
|
||||
* @return the number of status entries
|
||||
*/
|
||||
|
@ -97,7 +97,8 @@ typedef enum {
|
||||
(((S) & GIT_SUBMODULE_STATUS__INDEX_FLAGS) == 0)
|
||||
|
||||
#define GIT_SUBMODULE_STATUS_IS_WD_UNMODIFIED(S) \
|
||||
(((S) & GIT_SUBMODULE_STATUS__WD_FLAGS) == 0)
|
||||
(((S) & (GIT_SUBMODULE_STATUS__WD_FLAGS & \
|
||||
~GIT_SUBMODULE_STATUS_WD_UNINITIALIZED)) == 0)
|
||||
|
||||
#define GIT_SUBMODULE_STATUS_IS_WD_DIRTY(S) \
|
||||
(((S) & (GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED | \
|
||||
@ -114,29 +115,35 @@ typedef enum {
|
||||
*
|
||||
* - The submodule is not mentioned in the HEAD, the index, and the config,
|
||||
* but does "exist" in the working directory (i.e. there is a subdirectory
|
||||
* that is a valid self-contained git repo). In this case, this function
|
||||
* returns GIT_EEXISTS to indicate the the submodule exists but not in a
|
||||
* that appears to be a Git repository). In this case, this function
|
||||
* returns GIT_EEXISTS to indicate a sub-repository exists but not in a
|
||||
* state where a git_submodule can be instantiated.
|
||||
* - The submodule is not mentioned in the HEAD, index, or config and the
|
||||
* working directory doesn't contain a value git repo at that path.
|
||||
* There may or may not be anything else at that path, but nothing that
|
||||
* looks like a submodule. In this case, this returns GIT_ENOTFOUND.
|
||||
*
|
||||
* The submodule object is owned by the containing repo and will be freed
|
||||
* when the repo is freed. The caller need not free the submodule.
|
||||
* You must call `git_submodule_free` when done with the submodule.
|
||||
*
|
||||
* @param submodule Pointer to submodule description object pointer..
|
||||
* @param repo The repository.
|
||||
* @param name The name of the submodule. Trailing slashes will be ignored.
|
||||
* @param out Output ptr to submodule; pass NULL to just get return code
|
||||
* @param repo The parent repository
|
||||
* @param name The name of or path to the submodule; trailing slashes okay
|
||||
* @return 0 on success, GIT_ENOTFOUND if submodule does not exist,
|
||||
* GIT_EEXISTS if submodule exists in working directory only, -1 on
|
||||
* other errors.
|
||||
* GIT_EEXISTS if a repository is found in working directory only,
|
||||
* -1 on other errors.
|
||||
*/
|
||||
GIT_EXTERN(int) git_submodule_lookup(
|
||||
git_submodule **submodule,
|
||||
git_submodule **out,
|
||||
git_repository *repo,
|
||||
const char *name);
|
||||
|
||||
/**
|
||||
* Release a submodule
|
||||
*
|
||||
* @param submodule Submodule object
|
||||
*/
|
||||
GIT_EXTERN(void) git_submodule_free(git_submodule *submodule);
|
||||
|
||||
/**
|
||||
* Iterate over all tracked submodules of a repository.
|
||||
*
|
||||
@ -174,9 +181,11 @@ GIT_EXTERN(int) git_submodule_foreach(
|
||||
* `git_submodule_add_finalize()` to wrap up adding the new submodule and
|
||||
* .gitmodules to the index to be ready to commit.
|
||||
*
|
||||
* @param submodule The newly created submodule ready to open for clone
|
||||
* @param repo Superproject repository to contain the new submodule
|
||||
* @param url URL for the submodules remote
|
||||
* You must call `git_submodule_free` on the submodule object when done.
|
||||
*
|
||||
* @param out The newly created submodule ready to open for clone
|
||||
* @param repo The repository in which you want to create the submodule
|
||||
* @param url URL for the submodule's remote
|
||||
* @param path Path at which the submodule should be created
|
||||
* @param use_gitlink Should workdir contain a gitlink to the repo in
|
||||
* .git/modules vs. repo directly in workdir.
|
||||
@ -184,7 +193,7 @@ GIT_EXTERN(int) git_submodule_foreach(
|
||||
* -1 on other errors.
|
||||
*/
|
||||
GIT_EXTERN(int) git_submodule_add_setup(
|
||||
git_submodule **submodule,
|
||||
git_submodule **out,
|
||||
git_repository *repo,
|
||||
const char *url,
|
||||
const char *path,
|
||||
@ -270,6 +279,24 @@ GIT_EXTERN(const char *) git_submodule_path(git_submodule *submodule);
|
||||
*/
|
||||
GIT_EXTERN(const char *) git_submodule_url(git_submodule *submodule);
|
||||
|
||||
/**
|
||||
* Resolve a submodule url relative to the given repository.
|
||||
*
|
||||
* @param out buffer to store the absolute submodule url in
|
||||
* @param repo Pointer to repository object
|
||||
* @param url Relative url
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *url);
|
||||
|
||||
/**
|
||||
* Get the branch for the submodule.
|
||||
*
|
||||
* @param submodule Pointer to submodule object
|
||||
* @return Pointer to the submodule branch
|
||||
*/
|
||||
GIT_EXTERN(const char *) git_submodule_branch(git_submodule *submodule);
|
||||
|
||||
/**
|
||||
* Set the URL for the submodule.
|
||||
*
|
||||
@ -410,7 +437,7 @@ GIT_EXTERN(git_submodule_update_t) git_submodule_set_update(
|
||||
*
|
||||
* @return 0 if fetchRecurseSubmodules is false, 1 if true
|
||||
*/
|
||||
GIT_EXTERN(int) git_submodule_fetch_recurse_submodules(
|
||||
GIT_EXTERN(git_submodule_recurse_t) git_submodule_fetch_recurse_submodules(
|
||||
git_submodule *submodule);
|
||||
|
||||
/**
|
||||
@ -424,9 +451,9 @@ GIT_EXTERN(int) git_submodule_fetch_recurse_submodules(
|
||||
* @param fetch_recurse_submodules Boolean value
|
||||
* @return old value for fetchRecurseSubmodules
|
||||
*/
|
||||
GIT_EXTERN(int) git_submodule_set_fetch_recurse_submodules(
|
||||
GIT_EXTERN(git_submodule_recurse_t) git_submodule_set_fetch_recurse_submodules(
|
||||
git_submodule *submodule,
|
||||
int fetch_recurse_submodules);
|
||||
git_submodule_recurse_t fetch_recurse_submodules);
|
||||
|
||||
/**
|
||||
* Copy submodule info into ".git/config" file.
|
||||
@ -474,15 +501,23 @@ GIT_EXTERN(int) git_submodule_open(
|
||||
*
|
||||
* Call this to reread cached submodule information for this submodule if
|
||||
* you have reason to believe that it has changed.
|
||||
*
|
||||
* @param submodule The submodule to reload
|
||||
* @param force Force reload even if the data doesn't seem out of date
|
||||
* @return 0 on success, <0 on error
|
||||
*/
|
||||
GIT_EXTERN(int) git_submodule_reload(git_submodule *submodule);
|
||||
GIT_EXTERN(int) git_submodule_reload(git_submodule *submodule, int force);
|
||||
|
||||
/**
|
||||
* Reread all submodule info.
|
||||
*
|
||||
* Call this to reload all cached submodule information for the repo.
|
||||
*
|
||||
* @param repo The repository to reload submodule data for
|
||||
* @param force Force full reload even if the data doesn't seem out of date
|
||||
* @return 0 on success, <0 on error
|
||||
*/
|
||||
GIT_EXTERN(int) git_submodule_reload_all(git_repository *repo);
|
||||
GIT_EXTERN(int) git_submodule_reload_all(git_repository *repo, int force);
|
||||
|
||||
/**
|
||||
* Get the status for a submodule.
|
||||
|
@ -21,16 +21,18 @@
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Create new commit in the repository from a list of `git_oid` values
|
||||
* Create new commit in the repository from a list of `git_oid` values.
|
||||
*
|
||||
* See documentation for `git_commit_create()` for information about the
|
||||
* parameters, as the meaning is identical excepting that `tree` and
|
||||
* `parents` now take `git_oid`. This is a dangerous API in that nor
|
||||
* the `tree`, neither the `parents` list of `git_oid`s are checked for
|
||||
* validity.
|
||||
*
|
||||
* @see git_commit_create
|
||||
*/
|
||||
GIT_EXTERN(int) git_commit_create_from_oids(
|
||||
git_oid *oid,
|
||||
GIT_EXTERN(int) git_commit_create_from_ids(
|
||||
git_oid *id,
|
||||
git_repository *repo,
|
||||
const char *update_ref,
|
||||
const git_signature *author,
|
||||
@ -38,9 +40,41 @@ GIT_EXTERN(int) git_commit_create_from_oids(
|
||||
const char *message_encoding,
|
||||
const char *message,
|
||||
const git_oid *tree,
|
||||
int parent_count,
|
||||
size_t parent_count,
|
||||
const git_oid *parents[]);
|
||||
|
||||
/**
|
||||
* Callback function to return parents for commit.
|
||||
*
|
||||
* This is invoked with the count of the number of parents processed so far
|
||||
* along with the user supplied payload. This should return a git_oid of
|
||||
* the next parent or NULL if all parents have been provided.
|
||||
*/
|
||||
typedef const git_oid *(*git_commit_parent_callback)(size_t idx, void *payload);
|
||||
|
||||
/**
|
||||
* Create a new commit in the repository with an callback to supply parents.
|
||||
*
|
||||
* See documentation for `git_commit_create()` for information about the
|
||||
* parameters, as the meaning is identical excepting that `tree` takes a
|
||||
* `git_oid` and doesn't check for validity, and `parent_cb` is invoked
|
||||
* with `parent_payload` and should return `git_oid` values or NULL to
|
||||
* indicate that all parents are accounted for.
|
||||
*
|
||||
* @see git_commit_create
|
||||
*/
|
||||
GIT_EXTERN(int) git_commit_create_from_callback(
|
||||
git_oid *id,
|
||||
git_repository *repo,
|
||||
const char *update_ref,
|
||||
const git_signature *author,
|
||||
const git_signature *committer,
|
||||
const char *message_encoding,
|
||||
const char *message,
|
||||
const git_oid *tree,
|
||||
git_commit_parent_callback parent_cb,
|
||||
void *parent_payload);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
#endif
|
||||
|
@ -57,18 +57,32 @@ struct git_config_backend {
|
||||
|
||||
/* Open means open the file/database and parse if necessary */
|
||||
int (*open)(struct git_config_backend *, git_config_level_t level);
|
||||
int (*get)(const struct git_config_backend *, const char *key, const git_config_entry **entry);
|
||||
int (*get)(struct git_config_backend *, const char *key, const git_config_entry **entry);
|
||||
int (*set)(struct git_config_backend *, const char *key, const char *value);
|
||||
int (*set_multivar)(git_config_backend *cfg, const char *name, const char *regexp, const char *value);
|
||||
int (*del)(struct git_config_backend *, const char *key);
|
||||
int (*del_multivar)(struct git_config_backend *, const char *key, const char *regexp);
|
||||
int (*iterator)(git_config_iterator **, struct git_config_backend *);
|
||||
int (*refresh)(struct git_config_backend *);
|
||||
/** Produce a read-only version of this backend */
|
||||
int (*snapshot)(struct git_config_backend **, struct git_config_backend *);
|
||||
void (*free)(struct git_config_backend *);
|
||||
};
|
||||
#define GIT_CONFIG_BACKEND_VERSION 1
|
||||
#define GIT_CONFIG_BACKEND_INIT {GIT_CONFIG_BACKEND_VERSION}
|
||||
|
||||
/**
|
||||
* Initializes a `git_config_backend` with default values. Equivalent to
|
||||
* creating an instance with GIT_CONFIG_BACKEND_INIT.
|
||||
*
|
||||
* @param opts the `git_config_backend` struct to initialize.
|
||||
* @param version Version of struct; pass `GIT_CONFIG_BACKEND_VERSION`
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_init_backend(
|
||||
git_config_backend *backend,
|
||||
unsigned int version);
|
||||
|
||||
/**
|
||||
* Add a generic config file instance to an existing config
|
||||
*
|
||||
|
91
include/git2/sys/diff.h
Normal file
91
include/git2/sys/diff.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) the libgit2 contributors. All rights reserved.
|
||||
*
|
||||
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
||||
* a Linking Exception. For full terms see the included COPYING file.
|
||||
*/
|
||||
#ifndef INCLUDE_sys_git_diff_h__
|
||||
#define INCLUDE_sys_git_diff_h__
|
||||
|
||||
#include "git2/common.h"
|
||||
#include "git2/types.h"
|
||||
#include "git2/oid.h"
|
||||
#include "git2/diff.h"
|
||||
#include "git2/status.h"
|
||||
|
||||
/**
|
||||
* @file git2/sys/diff.h
|
||||
* @brief Low-level Git diff utilities
|
||||
* @ingroup Git
|
||||
* @{
|
||||
*/
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Diff print callback that writes to a git_buf.
|
||||
*
|
||||
* This function is provided not for you to call it directly, but instead
|
||||
* so you can use it as a function pointer to the `git_diff_print` or
|
||||
* `git_patch_print` APIs. When using those APIs, you specify a callback
|
||||
* to actually handle the diff and/or patch data.
|
||||
*
|
||||
* Use this callback to easily write that data to a `git_buf` buffer. You
|
||||
* must pass a `git_buf *` value as the payload to the `git_diff_print`
|
||||
* and/or `git_patch_print` function. The data will be appended to the
|
||||
* buffer (after any existing content).
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_print_callback__to_buf(
|
||||
const git_diff_delta *delta,
|
||||
const git_diff_hunk *hunk,
|
||||
const git_diff_line *line,
|
||||
void *payload); /*< payload must be a `git_buf *` */
|
||||
|
||||
/**
|
||||
* Diff print callback that writes to stdio FILE handle.
|
||||
*
|
||||
* This function is provided not for you to call it directly, but instead
|
||||
* so you can use it as a function pointer to the `git_diff_print` or
|
||||
* `git_patch_print` APIs. When using those APIs, you specify a callback
|
||||
* to actually handle the diff and/or patch data.
|
||||
*
|
||||
* Use this callback to easily write that data to a stdio FILE handle. You
|
||||
* must pass a `FILE *` value (such as `stdout` or `stderr` or the return
|
||||
* value from `fopen()`) as the payload to the `git_diff_print`
|
||||
* and/or `git_patch_print` function. If you pass NULL, this will write
|
||||
* data to `stdout`.
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_print_callback__to_file_handle(
|
||||
const git_diff_delta *delta,
|
||||
const git_diff_hunk *hunk,
|
||||
const git_diff_line *line,
|
||||
void *payload); /*< payload must be a `FILE *` */
|
||||
|
||||
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
size_t stat_calls;
|
||||
size_t oid_calculations;
|
||||
} git_diff_perfdata;
|
||||
|
||||
#define GIT_DIFF_PERFDATA_VERSION 1
|
||||
#define GIT_DIFF_PERFDATA_INIT {GIT_DIFF_PERFDATA_VERSION,0,0}
|
||||
|
||||
/**
|
||||
* Get performance data for a diff object.
|
||||
*
|
||||
* @param out Structure to be filled with diff performance data
|
||||
* @param diff Diff to read performance data from
|
||||
* @return 0 for success, <0 for error
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_get_perfdata(
|
||||
git_diff_perfdata *out, const git_diff *diff);
|
||||
|
||||
/**
|
||||
* Get performance data for diffs from a git_status_list
|
||||
*/
|
||||
GIT_EXTERN(int) git_status_list_get_perfdata(
|
||||
git_diff_perfdata *out, const git_status_list *status);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
#endif
|
@ -55,7 +55,10 @@ GIT_EXTERN(git_filter *) git_filter_lookup(const char *name);
|
||||
* your own chains of filters.
|
||||
*/
|
||||
GIT_EXTERN(int) git_filter_list_new(
|
||||
git_filter_list **out, git_repository *repo, git_filter_mode_t mode);
|
||||
git_filter_list **out,
|
||||
git_repository *repo,
|
||||
git_filter_mode_t mode,
|
||||
uint32_t options);
|
||||
|
||||
/**
|
||||
* Add a filter to a filter list with the given payload.
|
||||
@ -115,10 +118,15 @@ GIT_EXTERN(uint16_t) git_filter_source_filemode(const git_filter_source *src);
|
||||
GIT_EXTERN(const git_oid *) git_filter_source_id(const git_filter_source *src);
|
||||
|
||||
/**
|
||||
* Get the git_filter_mode_t to be applied
|
||||
* Get the git_filter_mode_t to be used
|
||||
*/
|
||||
GIT_EXTERN(git_filter_mode_t) git_filter_source_mode(const git_filter_source *src);
|
||||
|
||||
/**
|
||||
* Get the combination git_filter_opt_t options to be applied
|
||||
*/
|
||||
GIT_EXTERN(uint32_t) git_filter_source_options(const git_filter_source *src);
|
||||
|
||||
/*
|
||||
* struct git_filter
|
||||
*
|
||||
@ -149,6 +157,7 @@ typedef int (*git_filter_init_fn)(git_filter *self);
|
||||
* Specified as `filter.shutdown`, this is an optional callback invoked
|
||||
* when the filter is unregistered or when libgit2 is shutting down. It
|
||||
* will be called once at most and should release resources as needed.
|
||||
* This may be called even if the `initialize` callback was not made.
|
||||
*
|
||||
* Typically this function will free the `git_filter` object itself.
|
||||
*/
|
||||
|
85
include/git2/sys/mempack.h
Normal file
85
include/git2/sys/mempack.h
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) the libgit2 contributors. All rights reserved.
|
||||
*
|
||||
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
||||
* a Linking Exception. For full terms see the included COPYING file.
|
||||
*/
|
||||
#ifndef INCLUDE_sys_git_odb_mempack_h__
|
||||
#define INCLUDE_sys_git_odb_mempack_h__
|
||||
|
||||
#include "git2/common.h"
|
||||
#include "git2/types.h"
|
||||
#include "git2/oid.h"
|
||||
#include "git2/odb.h"
|
||||
|
||||
/**
|
||||
* @file git2/sys/mempack.h
|
||||
* @brief Custom ODB backend that permits packing objects in-memory
|
||||
* @defgroup git_backend Git custom backend APIs
|
||||
* @ingroup Git
|
||||
* @{
|
||||
*/
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Instantiate a new mempack backend.
|
||||
*
|
||||
* The backend must be added to an existing ODB with the highest
|
||||
* priority.
|
||||
*
|
||||
* git_mempack_new(&mempacker);
|
||||
* git_repository_odb(&odb, repository);
|
||||
* git_odb_add_backend(odb, mempacker, 999);
|
||||
*
|
||||
* Once the backend has been loaded, all writes to the ODB will
|
||||
* instead be queued in memory, and can be finalized with
|
||||
* `git_mempack_dump`.
|
||||
*
|
||||
* Subsequent reads will also be served from the in-memory store
|
||||
* to ensure consistency, until the memory store is dumped.
|
||||
*
|
||||
* @param out Poiter where to store the ODB backend
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
int git_mempack_new(git_odb_backend **out);
|
||||
|
||||
/**
|
||||
* Dump all the queued in-memory writes to a packfile.
|
||||
*
|
||||
* The contents of the packfile will be stored in the given buffer.
|
||||
* It is the caller's responsability to ensure that the generated
|
||||
* packfile is available to the repository (e.g. by writing it
|
||||
* to disk, or doing something crazy like distributing it across
|
||||
* several copies of the repository over a network).
|
||||
*
|
||||
* Once the generated packfile is available to the repository,
|
||||
* call `git_mempack_reset` to cleanup the memory store.
|
||||
*
|
||||
* Calling `git_mempack_reset` before the packfile has been
|
||||
* written to disk will result in an inconsistent repository
|
||||
* (the objects in the memory store won't be accessible).
|
||||
*
|
||||
* @param pack Buffer where to store the raw packfile
|
||||
* @param repo The active repository where the backend is loaded
|
||||
* @param backend The mempack backend
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
int git_mempack_dump(git_buf *pack, git_repository *repo, git_odb_backend *backend);
|
||||
|
||||
/**
|
||||
* Reset the memory packer by clearing all the queued objects.
|
||||
*
|
||||
* This assumes that `git_mempack_dump` has been called before to
|
||||
* store all the queued objects into a single packfile.
|
||||
*
|
||||
* Alternatively, call `reset` without a previous dump to "undo"
|
||||
* all the recently written objects, giving transaction-like
|
||||
* semantics to the Git repository.
|
||||
*
|
||||
* @param backend The mempack backend
|
||||
*/
|
||||
void git_mempack_reset(git_odb_backend *backend);
|
||||
|
||||
GIT_END_DECL
|
||||
|
||||
#endif
|
@ -35,11 +35,8 @@ struct git_odb_backend {
|
||||
int (* read)(
|
||||
void **, size_t *, git_otype *, git_odb_backend *, const git_oid *);
|
||||
|
||||
/* To find a unique object given a prefix
|
||||
* of its oid.
|
||||
* The oid given must be so that the
|
||||
* remaining (GIT_OID_HEXSZ - len)*4 bits
|
||||
* are 0s.
|
||||
/* To find a unique object given a prefix of its oid. The oid given
|
||||
* must be so that the remaining (GIT_OID_HEXSZ - len)*4 bits are 0s.
|
||||
*/
|
||||
int (* read_prefix)(
|
||||
git_oid *, void **, size_t *, git_otype *,
|
||||
@ -64,6 +61,9 @@ struct git_odb_backend {
|
||||
int (* exists)(
|
||||
git_odb_backend *, const git_oid *);
|
||||
|
||||
int (* exists_prefix)(
|
||||
git_oid *, git_odb_backend *, const git_oid *, size_t);
|
||||
|
||||
/**
|
||||
* If the backend implements a refreshing mechanism, it should be exposed
|
||||
* through this endpoint. Each call to `git_odb_refresh()` will invoke it.
|
||||
@ -81,7 +81,7 @@ struct git_odb_backend {
|
||||
|
||||
int (* writepack)(
|
||||
git_odb_writepack **, git_odb_backend *, git_odb *odb,
|
||||
git_transfer_progress_callback progress_cb, void *progress_payload);
|
||||
git_transfer_progress_cb progress_cb, void *progress_payload);
|
||||
|
||||
void (* free)(git_odb_backend *);
|
||||
};
|
||||
@ -89,6 +89,18 @@ struct git_odb_backend {
|
||||
#define GIT_ODB_BACKEND_VERSION 1
|
||||
#define GIT_ODB_BACKEND_INIT {GIT_ODB_BACKEND_VERSION}
|
||||
|
||||
/**
|
||||
* Initializes a `git_odb_backend` with default values. Equivalent to
|
||||
* creating an instance with GIT_ODB_BACKEND_INIT.
|
||||
*
|
||||
* @param opts the `git_odb_backend` struct to initialize.
|
||||
* @param version Version the struct; pass `GIT_ODB_BACKEND_VERSION`
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_odb_init_backend(
|
||||
git_odb_backend *backend,
|
||||
unsigned int version);
|
||||
|
||||
GIT_EXTERN(void *) git_odb_backend_malloc(git_odb_backend *backend, size_t len);
|
||||
|
||||
GIT_END_DECL
|
||||
|
@ -93,17 +93,20 @@ struct git_refdb_backend {
|
||||
* must provide this function.
|
||||
*/
|
||||
int (*write)(git_refdb_backend *backend,
|
||||
const git_reference *ref, int force);
|
||||
const git_reference *ref, int force,
|
||||
const git_signature *who, const char *message,
|
||||
const git_oid *old, const char *old_target);
|
||||
|
||||
int (*rename)(
|
||||
git_reference **out, git_refdb_backend *backend,
|
||||
const char *old_name, const char *new_name, int force);
|
||||
const char *old_name, const char *new_name, int force,
|
||||
const git_signature *who, const char *message);
|
||||
|
||||
/**
|
||||
* Deletes the given reference from the refdb. A refdb implementation
|
||||
* must provide this function.
|
||||
*/
|
||||
int (*del)(git_refdb_backend *backend, const char *ref_name);
|
||||
int (*del)(git_refdb_backend *backend, const char *ref_name, const git_oid *old_id, const char *old_target);
|
||||
|
||||
/**
|
||||
* Suggests that the given refdb compress or optimize its references.
|
||||
@ -114,6 +117,17 @@ struct git_refdb_backend {
|
||||
*/
|
||||
int (*compress)(git_refdb_backend *backend);
|
||||
|
||||
/**
|
||||
* Query whether a particular reference has a log (may be empty)
|
||||
*/
|
||||
int (*has_log)(git_refdb_backend *backend, const char *refname);
|
||||
|
||||
/**
|
||||
* Make sure a particular reference will have a reflog which
|
||||
* will be appended to on writes.
|
||||
*/
|
||||
int (*ensure_log)(git_refdb_backend *backend, const char *refname);
|
||||
|
||||
/**
|
||||
* Frees any resources held by the refdb. A refdb implementation may
|
||||
* provide this function; if it is not provided, nothing will be done.
|
||||
@ -144,6 +158,18 @@ struct git_refdb_backend {
|
||||
#define GIT_REFDB_BACKEND_VERSION 1
|
||||
#define GIT_REFDB_BACKEND_INIT {GIT_REFDB_BACKEND_VERSION}
|
||||
|
||||
/**
|
||||
* Initializes a `git_refdb_backend` with default values. Equivalent to
|
||||
* creating an instance with GIT_REFDB_BACKEND_INIT.
|
||||
*
|
||||
* @param opts the `git_refdb_backend` struct to initialize
|
||||
* @param version Version of struct; pass `GIT_REFDB_BACKEND_VERSION`
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_refdb_init_backend(
|
||||
git_refdb_backend *backend,
|
||||
unsigned int version);
|
||||
|
||||
/**
|
||||
* Constructors for default filesystem-based refdb backend
|
||||
*
|
||||
|
@ -41,6 +41,9 @@ typedef enum {
|
||||
|
||||
/* git_cred_default */
|
||||
GIT_CREDTYPE_DEFAULT = (1u << 3),
|
||||
|
||||
/* git_cred_ssh_interactive */
|
||||
GIT_CREDTYPE_SSH_INTERACTIVE = (1u << 4),
|
||||
} git_credtype_t;
|
||||
|
||||
/* The base structure for all credential types */
|
||||
@ -60,8 +63,10 @@ typedef struct {
|
||||
|
||||
#ifdef GIT_SSH
|
||||
typedef LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*git_cred_sign_callback));
|
||||
typedef LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*git_cred_ssh_interactive_callback));
|
||||
#else
|
||||
typedef int (*git_cred_sign_callback)(void *, ...);
|
||||
typedef int (*git_cred_ssh_interactive_callback)(void *, ...);
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -75,6 +80,16 @@ typedef struct git_cred_ssh_key {
|
||||
char *passphrase;
|
||||
} git_cred_ssh_key;
|
||||
|
||||
/**
|
||||
* Keyboard-interactive based ssh authentication
|
||||
*/
|
||||
typedef struct git_cred_ssh_interactive {
|
||||
git_cred parent;
|
||||
char *username;
|
||||
git_cred_ssh_interactive_callback prompt_callback;
|
||||
void *payload;
|
||||
} git_cred_ssh_interactive;
|
||||
|
||||
/**
|
||||
* A key with a custom signature function
|
||||
*/
|
||||
@ -83,8 +98,8 @@ typedef struct git_cred_ssh_custom {
|
||||
char *username;
|
||||
char *publickey;
|
||||
size_t publickey_len;
|
||||
void *sign_callback;
|
||||
void *sign_data;
|
||||
git_cred_sign_callback sign_callback;
|
||||
void *payload;
|
||||
} git_cred_ssh_custom;
|
||||
|
||||
/** A key for NTLM/Kerberos "default" credentials */
|
||||
@ -130,6 +145,33 @@ GIT_EXTERN(int) git_cred_ssh_key_new(
|
||||
const char *privatekey,
|
||||
const char *passphrase);
|
||||
|
||||
/**
|
||||
* Create a new ssh keyboard-interactive based credential object.
|
||||
* The supplied credential parameter will be internally duplicated.
|
||||
*
|
||||
* @param username Username to use to authenticate.
|
||||
* @param prompt_callback The callback method used for prompts.
|
||||
* @param payload Additional data to pass to the callback.
|
||||
* @return 0 for success or an error code for failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_cred_ssh_interactive_new(
|
||||
git_cred **out,
|
||||
const char *username,
|
||||
git_cred_ssh_interactive_callback prompt_callback,
|
||||
void *payload);
|
||||
|
||||
/**
|
||||
* Create a new ssh key credential object used for querying an ssh-agent.
|
||||
* The supplied credential parameter will be internally duplicated.
|
||||
*
|
||||
* @param out The newly created credential object.
|
||||
* @param username username to use to authenticate
|
||||
* @return 0 for success or an error code for failure
|
||||
*/
|
||||
GIT_EXTERN(int) git_cred_ssh_key_from_agent(
|
||||
git_cred **out,
|
||||
const char *username);
|
||||
|
||||
/**
|
||||
* Create an ssh key credential with a custom signing function.
|
||||
*
|
||||
@ -144,8 +186,8 @@ GIT_EXTERN(int) git_cred_ssh_key_new(
|
||||
* @param username username to use to authenticate
|
||||
* @param publickey The bytes of the public key.
|
||||
* @param publickey_len The length of the public key in bytes.
|
||||
* @param sign_fn The callback method to sign the data during the challenge.
|
||||
* @param sign_data The data to pass to the sign function.
|
||||
* @param sign_callback The callback method to sign the data during the challenge.
|
||||
* @param payload Additional data to pass to the callback.
|
||||
* @return 0 for success or an error code for failure
|
||||
*/
|
||||
GIT_EXTERN(int) git_cred_ssh_custom_new(
|
||||
@ -153,8 +195,8 @@ GIT_EXTERN(int) git_cred_ssh_custom_new(
|
||||
const char *username,
|
||||
const char *publickey,
|
||||
size_t publickey_len,
|
||||
git_cred_sign_callback sign_fn,
|
||||
void *sign_data);
|
||||
git_cred_sign_callback sign_callback,
|
||||
void *payload);
|
||||
|
||||
/**
|
||||
* Create a "default" credential usable for Negotiate mechanisms like NTLM
|
||||
@ -173,7 +215,8 @@ GIT_EXTERN(int) git_cred_default_new(git_cred **out);
|
||||
* remote url, or NULL if not included.
|
||||
* - allowed_types: A bitmask stating which cred types are OK to return.
|
||||
* - payload: The payload provided when specifying this callback.
|
||||
* - returns 0 for success or non-zero to indicate an error
|
||||
* - returns 0 for success, < 0 to indicate an error, > 0 to indicate
|
||||
* no credential was acquired
|
||||
*/
|
||||
typedef int (*git_cred_acquire_cb)(
|
||||
git_cred **cred,
|
||||
@ -244,7 +287,7 @@ struct git_transport {
|
||||
git_transport *transport,
|
||||
git_repository *repo,
|
||||
git_transfer_progress *stats,
|
||||
git_transfer_progress_callback progress_cb,
|
||||
git_transfer_progress_cb progress_cb,
|
||||
void *progress_payload);
|
||||
|
||||
/* Checks to see if the transport is connected */
|
||||
@ -267,6 +310,18 @@ struct git_transport {
|
||||
#define GIT_TRANSPORT_VERSION 1
|
||||
#define GIT_TRANSPORT_INIT {GIT_TRANSPORT_VERSION}
|
||||
|
||||
/**
|
||||
* Initializes a `git_transport` with default values. Equivalent to
|
||||
* creating an instance with GIT_TRANSPORT_INIT.
|
||||
*
|
||||
* @param opts the `git_transport` struct to initialize
|
||||
* @param version Version of struct; pass `GIT_TRANSPORT_VERSION`
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_transport_init(
|
||||
git_transport *opts,
|
||||
unsigned int version);
|
||||
|
||||
/**
|
||||
* Function to use to create a transport from a URL. The transport database
|
||||
* is scanned to find a transport that implements the scheme of the URI (i.e.
|
||||
|
@ -121,11 +121,11 @@ GIT_EXTERN(const git_tree_entry *) git_tree_entry_byindex(
|
||||
* Warning: this must examine every entry in the tree, so it is not fast.
|
||||
*
|
||||
* @param tree a previously loaded tree.
|
||||
* @param oid the sha being looked for
|
||||
* @param id the sha being looked for
|
||||
* @return the tree entry; NULL if not found
|
||||
*/
|
||||
GIT_EXTERN(const git_tree_entry *) git_tree_entry_byoid(
|
||||
const git_tree *tree, const git_oid *oid);
|
||||
GIT_EXTERN(const git_tree_entry *) git_tree_entry_byid(
|
||||
const git_tree *tree, const git_oid *id);
|
||||
|
||||
/**
|
||||
* Retrieve a tree entry contained in a tree or in any of its subtrees,
|
||||
@ -150,10 +150,11 @@ GIT_EXTERN(int) git_tree_entry_bypath(
|
||||
* Create a copy of a tree entry. The returned copy is owned by the user,
|
||||
* and must be freed explicitly with `git_tree_entry_free()`.
|
||||
*
|
||||
* @param entry A tree entry to duplicate
|
||||
* @return a copy of the original entry or NULL on error (alloc failure)
|
||||
* @param dest pointer where to store the copy
|
||||
* @param source tree entry to duplicate
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(git_tree_entry *) git_tree_entry_dup(const git_tree_entry *entry);
|
||||
GIT_EXTERN(int) git_tree_entry_dup(git_tree_entry **dest, const git_tree_entry *source);
|
||||
|
||||
/**
|
||||
* Free a user-owned tree entry
|
||||
@ -332,11 +333,18 @@ GIT_EXTERN(int) git_treebuilder_insert(
|
||||
GIT_EXTERN(int) git_treebuilder_remove(
|
||||
git_treebuilder *bld, const char *filename);
|
||||
|
||||
/**
|
||||
* Callback for git_treebuilder_filter
|
||||
*
|
||||
* The return value is treated as a boolean, with zero indicating that the
|
||||
* entry should be left alone and any non-zero value meaning that the
|
||||
* entry should be removed from the treebuilder list (i.e. filtered out).
|
||||
*/
|
||||
typedef int (*git_treebuilder_filter_cb)(
|
||||
const git_tree_entry *entry, void *payload);
|
||||
|
||||
/**
|
||||
* Filter the entries in the tree
|
||||
* Selectively remove entries in the tree
|
||||
*
|
||||
* The `filter` callback will be called for each entry in the tree with a
|
||||
* pointer to the entry and the provided `payload`; if the callback returns
|
||||
@ -344,7 +352,7 @@ typedef int (*git_treebuilder_filter_cb)(
|
||||
*
|
||||
* @param bld Tree builder
|
||||
* @param filter Callback to filter entries
|
||||
* @param payload Extra data to pass to filter
|
||||
* @param payload Extra data to pass to filter callback
|
||||
*/
|
||||
GIT_EXTERN(void) git_treebuilder_filter(
|
||||
git_treebuilder *bld,
|
||||
|
@ -131,7 +131,7 @@ typedef struct git_treebuilder git_treebuilder;
|
||||
/** Memory representation of an index file. */
|
||||
typedef struct git_index git_index;
|
||||
|
||||
/** An interator for conflicts in the index. */
|
||||
/** An iterator for conflicts in the index. */
|
||||
typedef struct git_index_conflict_iterator git_index_conflict_iterator;
|
||||
|
||||
/** Memory representation of a set of config files */
|
||||
@ -154,15 +154,15 @@ typedef struct git_packbuilder git_packbuilder;
|
||||
|
||||
/** Time in a signature */
|
||||
typedef struct git_time {
|
||||
git_time_t time; /** time in seconds from epoch */
|
||||
int offset; /** timezone offset, in minutes */
|
||||
git_time_t time; /**< time in seconds from epoch */
|
||||
int offset; /**< timezone offset, in minutes */
|
||||
} git_time;
|
||||
|
||||
/** An action signature (e.g. for committers, taggers, etc) */
|
||||
typedef struct git_signature {
|
||||
char *name; /** full name of the author */
|
||||
char *email; /** email of the author */
|
||||
git_time when; /** time when the action happened */
|
||||
char *name; /**< full name of the author */
|
||||
char *email; /**< email of the author */
|
||||
git_time when; /**< time when the action happened */
|
||||
} git_signature;
|
||||
|
||||
/** In-memory representation of a reference. */
|
||||
@ -183,9 +183,9 @@ typedef struct git_status_list git_status_list;
|
||||
|
||||
/** Basic type of any Git reference. */
|
||||
typedef enum {
|
||||
GIT_REF_INVALID = 0, /** Invalid reference */
|
||||
GIT_REF_OID = 1, /** A reference which points at an object id */
|
||||
GIT_REF_SYMBOLIC = 2, /** A reference which points at another reference */
|
||||
GIT_REF_INVALID = 0, /**< Invalid reference */
|
||||
GIT_REF_OID = 1, /**< A reference which points at an object id */
|
||||
GIT_REF_SYMBOLIC = 2, /**< A reference which points at another reference */
|
||||
GIT_REF_LISTALL = GIT_REF_OID|GIT_REF_SYMBOLIC,
|
||||
} git_ref_t;
|
||||
|
||||
@ -193,6 +193,7 @@ typedef enum {
|
||||
typedef enum {
|
||||
GIT_BRANCH_LOCAL = 1,
|
||||
GIT_BRANCH_REMOTE = 2,
|
||||
GIT_BRANCH_ALL = GIT_BRANCH_LOCAL|GIT_BRANCH_REMOTE,
|
||||
} git_branch_t;
|
||||
|
||||
/** Valid modes for index and tree entries. */
|
||||
@ -240,7 +241,7 @@ typedef struct git_transfer_progress {
|
||||
* @param stats Structure containing information about the state of the transfer
|
||||
* @param payload Payload provided by caller
|
||||
*/
|
||||
typedef int (*git_transfer_progress_callback)(const git_transfer_progress *stats, void *payload);
|
||||
typedef int (*git_transfer_progress_cb)(const git_transfer_progress *stats, void *payload);
|
||||
|
||||
/**
|
||||
* Opaque structure representing a submodule.
|
||||
@ -313,16 +314,35 @@ typedef enum {
|
||||
* when we don't want any particular ignore rule to be specified.
|
||||
*/
|
||||
typedef enum {
|
||||
GIT_SUBMODULE_IGNORE_RESET = -1, /* reset to on-disk value */
|
||||
GIT_SUBMODULE_IGNORE_RESET = -1, /**< reset to on-disk value */
|
||||
|
||||
GIT_SUBMODULE_IGNORE_NONE = 1, /* any change or untracked == dirty */
|
||||
GIT_SUBMODULE_IGNORE_UNTRACKED = 2, /* dirty if tracked files change */
|
||||
GIT_SUBMODULE_IGNORE_DIRTY = 3, /* only dirty if HEAD moved */
|
||||
GIT_SUBMODULE_IGNORE_ALL = 4, /* never dirty */
|
||||
GIT_SUBMODULE_IGNORE_NONE = 1, /**< any change or untracked == dirty */
|
||||
GIT_SUBMODULE_IGNORE_UNTRACKED = 2, /**< dirty if tracked files change */
|
||||
GIT_SUBMODULE_IGNORE_DIRTY = 3, /**< only dirty if HEAD moved */
|
||||
GIT_SUBMODULE_IGNORE_ALL = 4, /**< never dirty */
|
||||
|
||||
GIT_SUBMODULE_IGNORE_DEFAULT = 0
|
||||
} git_submodule_ignore_t;
|
||||
|
||||
/**
|
||||
* Options for submodule recurse.
|
||||
*
|
||||
* Represent the value of `submodule.$name.fetchRecurseSubmodules`
|
||||
*
|
||||
* * GIT_SUBMODULE_RECURSE_RESET - reset to the on-disk value
|
||||
* * GIT_SUBMODULE_RECURSE_NO - do no recurse into submodules
|
||||
* * GIT_SUBMODULE_RECURSE_YES - recurse into submodules
|
||||
* * GIT_SUBMODULE_RECURSE_ONDEMAND - recurse into submodules only when
|
||||
* commit not already in local clone
|
||||
*/
|
||||
typedef enum {
|
||||
GIT_SUBMODULE_RECURSE_RESET = -1,
|
||||
|
||||
GIT_SUBMODULE_RECURSE_NO = 0,
|
||||
GIT_SUBMODULE_RECURSE_YES = 1,
|
||||
GIT_SUBMODULE_RECURSE_ONDEMAND = 2,
|
||||
} git_submodule_recurse_t;
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
|
||||
|
@ -7,9 +7,11 @@
|
||||
#ifndef INCLUDE_git_version_h__
|
||||
#define INCLUDE_git_version_h__
|
||||
|
||||
#define LIBGIT2_VERSION "0.20.0"
|
||||
#define LIBGIT2_VERSION "0.21.0"
|
||||
#define LIBGIT2_VER_MAJOR 0
|
||||
#define LIBGIT2_VER_MINOR 20
|
||||
#define LIBGIT2_VER_MINOR 21
|
||||
#define LIBGIT2_VER_REVISION 0
|
||||
|
||||
#define LIBGIT2_SOVERSION 21
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ -n "$COVERITY" ];
|
||||
then
|
||||
./script/coverity.sh;
|
||||
exit $?;
|
||||
fi
|
||||
|
||||
# Create a test repo which we can use for the online::push tests
|
||||
mkdir $HOME/_temp
|
||||
git init --bare $HOME/_temp/test.git
|
||||
@ -28,5 +34,5 @@ export GITTEST_REMOTE_SSH_PUBKEY="$HOME/.ssh/id_rsa.pub"
|
||||
export GITTEST_REMOTE_SSH_PASSPHRASE=""
|
||||
|
||||
if [ -e ./libgit2_clar ]; then
|
||||
./libgit2_clar -sonline::push
|
||||
./libgit2_clar -sonline::push -sonline::clone::cred_callback_failure
|
||||
fi
|
||||
|
57
script/coverity.sh
Executable file
57
script/coverity.sh
Executable file
@ -0,0 +1,57 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Environment check
|
||||
[ -z "$COVERITY_TOKEN" ] && echo "Need to set a coverity token" && exit 1
|
||||
|
||||
# Only run this on our branches
|
||||
echo "Pull request: $TRAVIS_PULL_REQUEST | Slug: $TRAVIS_REPO_SLUG"
|
||||
if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_REPO_SLUG" != "libgit2/libgit2" ];
|
||||
then
|
||||
echo "Only analyzing 'development' on the main repo."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
COV_VERSION=6.6.1
|
||||
case `uname -m` in
|
||||
i?86) BITS=32 ;;
|
||||
amd64|x86_64) BITS=64 ;;
|
||||
esac
|
||||
SCAN_TOOL=https://scan.coverity.com/download/linux-${BITS}
|
||||
TOOL_BASE=`pwd`/_coverity-scan
|
||||
|
||||
# Install coverity tools
|
||||
if [ ! -d $TOOL_BASE ]; then
|
||||
echo "Downloading coverity..."
|
||||
mkdir -p $TOOL_BASE
|
||||
cd $TOOL_BASE
|
||||
wget -O coverity_tool.tgz $SCAN_TOOL \
|
||||
--post-data "project=libgit2&token=$COVERITY_TOKEN"
|
||||
tar xzf coverity_tool.tgz
|
||||
cd ..
|
||||
TOOL_DIR=`find $TOOL_BASE -type d -name 'cov-analysis*'`
|
||||
ln -s $TOOL_DIR $TOOL_BASE/cov-analysis
|
||||
fi
|
||||
|
||||
COV_BUILD="$TOOL_BASE/cov-analysis/bin/cov-build"
|
||||
|
||||
# Configure and build
|
||||
rm -rf _build
|
||||
mkdir _build
|
||||
cd _build
|
||||
cmake .. -DTHREADSAFE=ON
|
||||
COVERITY_UNSUPPORTED=1 \
|
||||
$COV_BUILD --dir cov-int \
|
||||
cmake --build .
|
||||
|
||||
# Upload results
|
||||
tar czf libgit2.tgz cov-int
|
||||
SHA=`git rev-parse --short HEAD`
|
||||
curl \
|
||||
--form project=libgit2 \
|
||||
--form token=$COVERITY_TOKEN \
|
||||
--form email=bs@github.com \
|
||||
--form file=@libgit2.tgz \
|
||||
--form version=$SHA \
|
||||
--form description="Travis build" \
|
||||
http://scan5.coverity.com/cgi-bin/upload.py
|
6
script/install-deps-linux.sh
Executable file
6
script/install-deps-linux.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -x
|
||||
|
||||
sudo apt-get -qq update &&
|
||||
sudo apt-get -qq install cmake libssh2-1-dev openssh-client openssh-server
|
5
script/install-deps-osx.sh
Executable file
5
script/install-deps-osx.sh
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -x
|
||||
|
||||
brew install libssh2 cmake
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) the libgit2 contributors. All rights reserved.
|
||||
*
|
||||
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
||||
* a Linking Exception. For full terms see the included COPYING file.
|
||||
*/
|
||||
#include <git2/common.h>
|
||||
|
||||
#ifndef GIT_WIN32
|
||||
|
||||
#include "posix.h"
|
||||
#include "map.h"
|
||||
#include <errno.h>
|
||||
|
||||
int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset)
|
||||
{
|
||||
GIT_MMAP_VALIDATE(out, len, prot, flags);
|
||||
|
||||
out->data = NULL;
|
||||
out->len = 0;
|
||||
|
||||
if ((prot & GIT_PROT_WRITE) && ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED)) {
|
||||
giterr_set(GITERR_OS, "Trying to map shared-writeable");
|
||||
return -1;
|
||||
}
|
||||
|
||||
out->data = malloc(len);
|
||||
GITERR_CHECK_ALLOC(out->data);
|
||||
|
||||
if ((p_lseek(fd, offset, SEEK_SET) < 0) || ((size_t)p_read(fd, out->data, len) != len)) {
|
||||
giterr_set(GITERR_OS, "mmap emulation failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
out->len = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int p_munmap(git_map *map)
|
||||
{
|
||||
assert(map != NULL);
|
||||
free(map->data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -7,7 +7,7 @@
|
||||
#ifndef INCLUDE_array_h__
|
||||
#define INCLUDE_array_h__
|
||||
|
||||
#include "util.h"
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* Use this to declare a typesafe resizable array of items, a la:
|
||||
|
551
src/attr.c
551
src/attr.c
@ -1,8 +1,8 @@
|
||||
#include "common.h"
|
||||
#include "repository.h"
|
||||
#include "fileops.h"
|
||||
#include "sysdir.h"
|
||||
#include "config.h"
|
||||
#include "attr.h"
|
||||
#include "attr_file.h"
|
||||
#include "ignore.h"
|
||||
#include "git2/oid.h"
|
||||
#include <ctype.h>
|
||||
@ -33,6 +33,7 @@ static int collect_attr_files(
|
||||
const char *path,
|
||||
git_vector *files);
|
||||
|
||||
static void release_attr_files(git_vector *files);
|
||||
|
||||
int git_attr_get(
|
||||
const char **value,
|
||||
@ -49,6 +50,8 @@ int git_attr_get(
|
||||
git_attr_name attr;
|
||||
git_attr_rule *rule;
|
||||
|
||||
assert(value && repo && name);
|
||||
|
||||
*value = NULL;
|
||||
|
||||
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
|
||||
@ -57,6 +60,7 @@ int git_attr_get(
|
||||
if ((error = collect_attr_files(repo, flags, pathname, &files)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.name = name;
|
||||
attr.name_hash = git_attr_file__name_hash(name);
|
||||
|
||||
@ -74,7 +78,7 @@ int git_attr_get(
|
||||
}
|
||||
|
||||
cleanup:
|
||||
git_vector_free(&files);
|
||||
release_attr_files(&files);
|
||||
git_attr_path__free(&path);
|
||||
|
||||
return error;
|
||||
@ -103,6 +107,11 @@ int git_attr_get_many(
|
||||
attr_get_many_info *info = NULL;
|
||||
size_t num_found = 0;
|
||||
|
||||
if (!num_attr)
|
||||
return 0;
|
||||
|
||||
assert(values && repo && names);
|
||||
|
||||
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
|
||||
return -1;
|
||||
|
||||
@ -145,7 +154,7 @@ int git_attr_get_many(
|
||||
}
|
||||
|
||||
cleanup:
|
||||
git_vector_free(&files);
|
||||
release_attr_files(&files);
|
||||
git_attr_path__free(&path);
|
||||
git__free(info);
|
||||
|
||||
@ -169,15 +178,15 @@ int git_attr_foreach(
|
||||
git_attr_assignment *assign;
|
||||
git_strmap *seen = NULL;
|
||||
|
||||
assert(repo && callback);
|
||||
|
||||
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
|
||||
return -1;
|
||||
|
||||
if ((error = collect_attr_files(repo, flags, pathname, &files)) < 0)
|
||||
if ((error = collect_attr_files(repo, flags, pathname, &files)) < 0 ||
|
||||
(error = git_strmap_alloc(&seen)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
seen = git_strmap_alloc();
|
||||
GITERR_CHECK_ALLOC(seen);
|
||||
|
||||
git_vector_foreach(&files, i, file) {
|
||||
|
||||
git_attr_file__foreach_matching_rule(file, &path, j, rule) {
|
||||
@ -193,8 +202,7 @@ int git_attr_foreach(
|
||||
|
||||
error = callback(assign->name, assign->value, payload);
|
||||
if (error) {
|
||||
giterr_clear();
|
||||
error = GIT_EUSER;
|
||||
giterr_set_after_callback(error);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
@ -203,12 +211,79 @@ int git_attr_foreach(
|
||||
|
||||
cleanup:
|
||||
git_strmap_free(seen);
|
||||
git_vector_free(&files);
|
||||
release_attr_files(&files);
|
||||
git_attr_path__free(&path);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int preload_attr_file(
|
||||
git_repository *repo,
|
||||
git_attr_file_source source,
|
||||
const char *base,
|
||||
const char *file)
|
||||
{
|
||||
int error;
|
||||
git_attr_file *preload = NULL;
|
||||
|
||||
if (!file)
|
||||
return 0;
|
||||
if (!(error = git_attr_cache__get(
|
||||
&preload, repo, source, base, file, git_attr_file__parse_buffer)))
|
||||
git_attr_file__free(preload);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int attr_setup(git_repository *repo)
|
||||
{
|
||||
int error = 0;
|
||||
const char *workdir = git_repository_workdir(repo);
|
||||
git_index *idx = NULL;
|
||||
git_buf sys = GIT_BUF_INIT;
|
||||
|
||||
if ((error = git_attr_cache__init(repo)) < 0)
|
||||
return error;
|
||||
|
||||
/* preload attribute files that could contain macros so the
|
||||
* definitions will be available for later file parsing
|
||||
*/
|
||||
|
||||
if (!(error = git_sysdir_find_system_file(&sys, GIT_ATTR_FILE_SYSTEM))) {
|
||||
error = preload_attr_file(
|
||||
repo, GIT_ATTR_FILE__FROM_FILE, NULL, sys.ptr);
|
||||
git_buf_free(&sys);
|
||||
}
|
||||
if (error < 0) {
|
||||
if (error == GIT_ENOTFOUND) {
|
||||
giterr_clear();
|
||||
error = 0;
|
||||
} else
|
||||
return error;
|
||||
}
|
||||
|
||||
if ((error = preload_attr_file(
|
||||
repo, GIT_ATTR_FILE__FROM_FILE,
|
||||
NULL, git_repository_attr_cache(repo)->cfg_attr_file)) < 0)
|
||||
return error;
|
||||
|
||||
if ((error = preload_attr_file(
|
||||
repo, GIT_ATTR_FILE__FROM_FILE,
|
||||
git_repository_path(repo), GIT_ATTR_FILE_INREPO)) < 0)
|
||||
return error;
|
||||
|
||||
if (workdir != NULL &&
|
||||
(error = preload_attr_file(
|
||||
repo, GIT_ATTR_FILE__FROM_FILE, workdir, GIT_ATTR_FILE)) < 0)
|
||||
return error;
|
||||
|
||||
if ((error = git_repository_index__weakptr(&idx, repo)) < 0 ||
|
||||
(error = preload_attr_file(
|
||||
repo, GIT_ATTR_FILE__FROM_INDEX, NULL, GIT_ATTR_FILE)) < 0)
|
||||
return error;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_attr_add_macro(
|
||||
git_repository *repo,
|
||||
@ -219,8 +294,8 @@ int git_attr_add_macro(
|
||||
git_attr_rule *macro = NULL;
|
||||
git_pool *pool;
|
||||
|
||||
if (git_attr_cache__init(repo) < 0)
|
||||
return -1;
|
||||
if ((error = git_attr_cache__init(repo)) < 0)
|
||||
return error;
|
||||
|
||||
macro = git__calloc(1, sizeof(git_attr_rule));
|
||||
GITERR_CHECK_ALLOC(macro);
|
||||
@ -244,237 +319,6 @@ int git_attr_add_macro(
|
||||
return error;
|
||||
}
|
||||
|
||||
bool git_attr_cache__is_cached(
|
||||
git_repository *repo, git_attr_file_source source, const char *path)
|
||||
{
|
||||
git_buf cache_key = GIT_BUF_INIT;
|
||||
git_strmap *files = git_repository_attr_cache(repo)->files;
|
||||
const char *workdir = git_repository_workdir(repo);
|
||||
bool rval;
|
||||
|
||||
if (workdir && git__prefixcmp(path, workdir) == 0)
|
||||
path += strlen(workdir);
|
||||
if (git_buf_printf(&cache_key, "%d#%s", (int)source, path) < 0)
|
||||
return false;
|
||||
|
||||
rval = git_strmap_exists(files, git_buf_cstr(&cache_key));
|
||||
|
||||
git_buf_free(&cache_key);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
static int load_attr_file(
|
||||
const char **data,
|
||||
git_futils_filestamp *stamp,
|
||||
const char *filename)
|
||||
{
|
||||
int error;
|
||||
git_buf content = GIT_BUF_INIT;
|
||||
|
||||
error = git_futils_filestamp_check(stamp, filename);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
/* if error == 0, then file is up to date. By returning GIT_ENOTFOUND,
|
||||
* we tell the caller not to reparse this file...
|
||||
*/
|
||||
if (!error)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
error = git_futils_readbuffer(&content, filename);
|
||||
if (error < 0) {
|
||||
/* convert error into ENOTFOUND so failed permissions / invalid
|
||||
* file type don't actually stop the operation in progress.
|
||||
*/
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
/* TODO: once warnings are available, issue a warning callback */
|
||||
}
|
||||
|
||||
*data = git_buf_detach(&content);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_attr_blob_from_index(
|
||||
const char **content,
|
||||
git_blob **blob,
|
||||
git_repository *repo,
|
||||
const git_oid *old_oid,
|
||||
const char *relfile)
|
||||
{
|
||||
int error;
|
||||
size_t pos;
|
||||
git_index *index;
|
||||
const git_index_entry *entry;
|
||||
|
||||
if ((error = git_repository_index__weakptr(&index, repo)) < 0 ||
|
||||
(error = git_index_find(&pos, index, relfile)) < 0)
|
||||
return error;
|
||||
|
||||
entry = git_index_get_byindex(index, pos);
|
||||
|
||||
if (old_oid && git_oid__cmp(old_oid, &entry->oid) == 0)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
if ((error = git_blob_lookup(blob, repo, &entry->oid)) < 0)
|
||||
return error;
|
||||
|
||||
*content = git_blob_rawcontent(*blob);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_attr_from_cache(
|
||||
git_attr_file **file,
|
||||
git_attr_cache *cache,
|
||||
git_attr_file_source source,
|
||||
const char *relative_path)
|
||||
{
|
||||
git_buf cache_key = GIT_BUF_INIT;
|
||||
khiter_t cache_pos;
|
||||
|
||||
*file = NULL;
|
||||
|
||||
if (!cache || !cache->files)
|
||||
return 0;
|
||||
|
||||
if (git_buf_printf(&cache_key, "%d#%s", (int)source, relative_path) < 0)
|
||||
return -1;
|
||||
|
||||
cache_pos = git_strmap_lookup_index(cache->files, cache_key.ptr);
|
||||
|
||||
git_buf_free(&cache_key);
|
||||
|
||||
if (git_strmap_valid_index(cache->files, cache_pos))
|
||||
*file = git_strmap_value_at(cache->files, cache_pos);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_attr_cache__internal_file(
|
||||
git_repository *repo,
|
||||
const char *filename,
|
||||
git_attr_file **file)
|
||||
{
|
||||
int error = 0;
|
||||
git_attr_cache *cache = git_repository_attr_cache(repo);
|
||||
khiter_t cache_pos = git_strmap_lookup_index(cache->files, filename);
|
||||
|
||||
if (git_strmap_valid_index(cache->files, cache_pos)) {
|
||||
*file = git_strmap_value_at(cache->files, cache_pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (git_attr_file__new(file, 0, filename, &cache->pool) < 0)
|
||||
return -1;
|
||||
|
||||
git_strmap_insert(cache->files, (*file)->key + 2, *file, error);
|
||||
if (error > 0)
|
||||
error = 0;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_attr_cache__push_file(
|
||||
git_repository *repo,
|
||||
const char *base,
|
||||
const char *filename,
|
||||
git_attr_file_source source,
|
||||
git_attr_file_parser parse,
|
||||
void* parsedata,
|
||||
git_vector *stack)
|
||||
{
|
||||
int error = 0;
|
||||
git_buf path = GIT_BUF_INIT;
|
||||
const char *workdir = git_repository_workdir(repo);
|
||||
const char *relfile, *content = NULL;
|
||||
git_attr_cache *cache = git_repository_attr_cache(repo);
|
||||
git_attr_file *file = NULL;
|
||||
git_blob *blob = NULL;
|
||||
git_futils_filestamp stamp;
|
||||
|
||||
assert(filename && stack);
|
||||
|
||||
/* join base and path as needed */
|
||||
if (base != NULL && git_path_root(filename) < 0) {
|
||||
if (git_buf_joinpath(&path, base, filename) < 0)
|
||||
return -1;
|
||||
filename = path.ptr;
|
||||
}
|
||||
|
||||
relfile = filename;
|
||||
if (workdir && git__prefixcmp(relfile, workdir) == 0)
|
||||
relfile += strlen(workdir);
|
||||
|
||||
/* check cache */
|
||||
if (load_attr_from_cache(&file, cache, source, relfile) < 0)
|
||||
return -1;
|
||||
|
||||
/* if not in cache, load data, parse, and cache */
|
||||
|
||||
if (source == GIT_ATTR_FILE_FROM_FILE) {
|
||||
git_futils_filestamp_set(
|
||||
&stamp, file ? &file->cache_data.stamp : NULL);
|
||||
|
||||
error = load_attr_file(&content, &stamp, filename);
|
||||
} else {
|
||||
error = load_attr_blob_from_index(&content, &blob,
|
||||
repo, file ? &file->cache_data.oid : NULL, relfile);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
/* not finding a file is not an error for this function */
|
||||
if (error == GIT_ENOTFOUND) {
|
||||
giterr_clear();
|
||||
error = 0;
|
||||
}
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* if we got here, we have to parse and/or reparse the file */
|
||||
if (file)
|
||||
git_attr_file__clear_rules(file);
|
||||
else {
|
||||
error = git_attr_file__new(&file, source, relfile, &cache->pool);
|
||||
if (error < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (parse && (error = parse(repo, parsedata, content, file)) < 0)
|
||||
goto finish;
|
||||
|
||||
git_strmap_insert(cache->files, file->key, file, error); //-V595
|
||||
if (error > 0)
|
||||
error = 0;
|
||||
|
||||
/* remember "cache buster" file signature */
|
||||
if (blob)
|
||||
git_oid_cpy(&file->cache_data.oid, git_object_id((git_object *)blob));
|
||||
else
|
||||
git_futils_filestamp_set(&file->cache_data.stamp, &stamp);
|
||||
|
||||
finish:
|
||||
/* push file onto vector if we found one*/
|
||||
if (!error && file != NULL)
|
||||
error = git_vector_insert(stack, file);
|
||||
|
||||
if (error != 0)
|
||||
git_attr_file__free(file);
|
||||
|
||||
if (blob)
|
||||
git_blob_free(blob);
|
||||
else
|
||||
git__free((void *)content);
|
||||
|
||||
git_buf_free(&path);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
#define push_attr_file(R,S,B,F) \
|
||||
git_attr_cache__push_file((R),(B),(F),GIT_ATTR_FILE_FROM_FILE,git_attr_file__parse_buffer,NULL,(S))
|
||||
|
||||
typedef struct {
|
||||
git_repository *repo;
|
||||
uint32_t flags;
|
||||
@ -483,7 +327,7 @@ typedef struct {
|
||||
git_vector *files;
|
||||
} attr_walk_up_info;
|
||||
|
||||
int git_attr_cache__decide_sources(
|
||||
static int attr_decide_sources(
|
||||
uint32_t flags, bool has_wd, bool has_index, git_attr_file_source *srcs)
|
||||
{
|
||||
int count = 0;
|
||||
@ -491,42 +335,76 @@ int git_attr_cache__decide_sources(
|
||||
switch (flags & 0x03) {
|
||||
case GIT_ATTR_CHECK_FILE_THEN_INDEX:
|
||||
if (has_wd)
|
||||
srcs[count++] = GIT_ATTR_FILE_FROM_FILE;
|
||||
srcs[count++] = GIT_ATTR_FILE__FROM_FILE;
|
||||
if (has_index)
|
||||
srcs[count++] = GIT_ATTR_FILE_FROM_INDEX;
|
||||
srcs[count++] = GIT_ATTR_FILE__FROM_INDEX;
|
||||
break;
|
||||
case GIT_ATTR_CHECK_INDEX_THEN_FILE:
|
||||
if (has_index)
|
||||
srcs[count++] = GIT_ATTR_FILE_FROM_INDEX;
|
||||
srcs[count++] = GIT_ATTR_FILE__FROM_INDEX;
|
||||
if (has_wd)
|
||||
srcs[count++] = GIT_ATTR_FILE_FROM_FILE;
|
||||
srcs[count++] = GIT_ATTR_FILE__FROM_FILE;
|
||||
break;
|
||||
case GIT_ATTR_CHECK_INDEX_ONLY:
|
||||
if (has_index)
|
||||
srcs[count++] = GIT_ATTR_FILE_FROM_INDEX;
|
||||
srcs[count++] = GIT_ATTR_FILE__FROM_INDEX;
|
||||
break;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int push_attr_file(
|
||||
git_repository *repo,
|
||||
git_vector *list,
|
||||
git_attr_file_source source,
|
||||
const char *base,
|
||||
const char *filename)
|
||||
{
|
||||
int error = 0;
|
||||
git_attr_file *file = NULL;
|
||||
|
||||
error = git_attr_cache__get(
|
||||
&file, repo, source, base, filename, git_attr_file__parse_buffer);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
if (file != NULL) {
|
||||
if ((error = git_vector_insert(list, file)) < 0)
|
||||
git_attr_file__free(file);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int push_one_attr(void *ref, git_buf *path)
|
||||
{
|
||||
int error = 0, n_src, i;
|
||||
attr_walk_up_info *info = (attr_walk_up_info *)ref;
|
||||
git_attr_file_source src[2];
|
||||
|
||||
n_src = git_attr_cache__decide_sources(
|
||||
n_src = attr_decide_sources(
|
||||
info->flags, info->workdir != NULL, info->index != NULL, src);
|
||||
|
||||
for (i = 0; !error && i < n_src; ++i)
|
||||
error = git_attr_cache__push_file(
|
||||
info->repo, path->ptr, GIT_ATTR_FILE, src[i],
|
||||
git_attr_file__parse_buffer, NULL, info->files);
|
||||
error = push_attr_file(
|
||||
info->repo, info->files, src[i], path->ptr, GIT_ATTR_FILE);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static void release_attr_files(git_vector *files)
|
||||
{
|
||||
size_t i;
|
||||
git_attr_file *file;
|
||||
|
||||
git_vector_foreach(files, i, file) {
|
||||
git_attr_file__free(file);
|
||||
files->contents[i] = NULL;
|
||||
}
|
||||
git_vector_free(files);
|
||||
}
|
||||
|
||||
static int collect_attr_files(
|
||||
git_repository *repo,
|
||||
uint32_t flags,
|
||||
@ -536,11 +414,10 @@ static int collect_attr_files(
|
||||
int error;
|
||||
git_buf dir = GIT_BUF_INIT;
|
||||
const char *workdir = git_repository_workdir(repo);
|
||||
attr_walk_up_info info;
|
||||
attr_walk_up_info info = { NULL };
|
||||
|
||||
if (git_attr_cache__init(repo) < 0 ||
|
||||
git_vector_init(files, 4, NULL) < 0)
|
||||
return -1;
|
||||
if ((error = attr_setup(repo)) < 0)
|
||||
return error;
|
||||
|
||||
/* Resolve path in a non-bare repo */
|
||||
if (workdir != NULL)
|
||||
@ -558,7 +435,8 @@ static int collect_attr_files(
|
||||
*/
|
||||
|
||||
error = push_attr_file(
|
||||
repo, files, git_repository_path(repo), GIT_ATTR_FILE_INREPO);
|
||||
repo, files, GIT_ATTR_FILE__FROM_FILE,
|
||||
git_repository_path(repo), GIT_ATTR_FILE_INREPO);
|
||||
if (error < 0)
|
||||
goto cleanup;
|
||||
|
||||
@ -575,15 +453,17 @@ static int collect_attr_files(
|
||||
|
||||
if (git_repository_attr_cache(repo)->cfg_attr_file != NULL) {
|
||||
error = push_attr_file(
|
||||
repo, files, NULL, git_repository_attr_cache(repo)->cfg_attr_file);
|
||||
repo, files, GIT_ATTR_FILE__FROM_FILE,
|
||||
NULL, git_repository_attr_cache(repo)->cfg_attr_file);
|
||||
if (error < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((flags & GIT_ATTR_CHECK_NO_SYSTEM) == 0) {
|
||||
error = git_futils_find_system_file(&dir, GIT_ATTR_FILE_SYSTEM);
|
||||
error = git_sysdir_find_system_file(&dir, GIT_ATTR_FILE_SYSTEM);
|
||||
if (!error)
|
||||
error = push_attr_file(repo, files, NULL, dir.ptr);
|
||||
error = push_attr_file(
|
||||
repo, files, GIT_ATTR_FILE__FROM_FILE, NULL, dir.ptr);
|
||||
else if (error == GIT_ENOTFOUND) {
|
||||
giterr_clear();
|
||||
error = 0;
|
||||
@ -592,153 +472,8 @@ static int collect_attr_files(
|
||||
|
||||
cleanup:
|
||||
if (error < 0)
|
||||
git_vector_free(files);
|
||||
release_attr_files(files);
|
||||
git_buf_free(&dir);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int attr_cache__lookup_path(
|
||||
char **out, git_config *cfg, const char *key, const char *fallback)
|
||||
{
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
int error;
|
||||
const char *cfgval = NULL;
|
||||
|
||||
*out = NULL;
|
||||
|
||||
if (!(error = git_config_get_string(&cfgval, cfg, key))) {
|
||||
|
||||
/* expand leading ~/ as needed */
|
||||
if (cfgval && cfgval[0] == '~' && cfgval[1] == '/' &&
|
||||
!git_futils_find_global_file(&buf, &cfgval[2]))
|
||||
*out = git_buf_detach(&buf);
|
||||
else if (cfgval)
|
||||
*out = git__strdup(cfgval);
|
||||
|
||||
} else if (error == GIT_ENOTFOUND) {
|
||||
giterr_clear();
|
||||
error = 0;
|
||||
|
||||
if (!git_futils_find_xdg_file(&buf, fallback))
|
||||
*out = git_buf_detach(&buf);
|
||||
}
|
||||
|
||||
git_buf_free(&buf);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_attr_cache__init(git_repository *repo)
|
||||
{
|
||||
int ret;
|
||||
git_attr_cache *cache = git_repository_attr_cache(repo);
|
||||
git_config *cfg;
|
||||
|
||||
if (cache->initialized)
|
||||
return 0;
|
||||
|
||||
/* cache config settings for attributes and ignores */
|
||||
if (git_repository_config__weakptr(&cfg, repo) < 0)
|
||||
return -1;
|
||||
|
||||
ret = attr_cache__lookup_path(
|
||||
&cache->cfg_attr_file, cfg, GIT_ATTR_CONFIG, GIT_ATTR_FILE_XDG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = attr_cache__lookup_path(
|
||||
&cache->cfg_excl_file, cfg, GIT_IGNORE_CONFIG, GIT_IGNORE_FILE_XDG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* allocate hashtable for attribute and ignore file contents */
|
||||
if (cache->files == NULL) {
|
||||
cache->files = git_strmap_alloc();
|
||||
GITERR_CHECK_ALLOC(cache->files);
|
||||
}
|
||||
|
||||
/* allocate hashtable for attribute macros */
|
||||
if (cache->macros == NULL) {
|
||||
cache->macros = git_strmap_alloc();
|
||||
GITERR_CHECK_ALLOC(cache->macros);
|
||||
}
|
||||
|
||||
/* allocate string pool */
|
||||
if (git_pool_init(&cache->pool, 1, 0) < 0)
|
||||
return -1;
|
||||
|
||||
cache->initialized = 1;
|
||||
|
||||
/* insert default macros */
|
||||
return git_attr_add_macro(repo, "binary", "-diff -crlf -text");
|
||||
}
|
||||
|
||||
void git_attr_cache_flush(
|
||||
git_repository *repo)
|
||||
{
|
||||
git_attr_cache *cache;
|
||||
|
||||
if (!repo)
|
||||
return;
|
||||
|
||||
cache = git_repository_attr_cache(repo);
|
||||
|
||||
if (cache->files != NULL) {
|
||||
git_attr_file *file;
|
||||
|
||||
git_strmap_foreach_value(cache->files, file, {
|
||||
git_attr_file__free(file);
|
||||
});
|
||||
|
||||
git_strmap_free(cache->files);
|
||||
}
|
||||
|
||||
if (cache->macros != NULL) {
|
||||
git_attr_rule *rule;
|
||||
|
||||
git_strmap_foreach_value(cache->macros, rule, {
|
||||
git_attr_rule__free(rule);
|
||||
});
|
||||
|
||||
git_strmap_free(cache->macros);
|
||||
}
|
||||
|
||||
git_pool_clear(&cache->pool);
|
||||
|
||||
git__free(cache->cfg_attr_file);
|
||||
cache->cfg_attr_file = NULL;
|
||||
|
||||
git__free(cache->cfg_excl_file);
|
||||
cache->cfg_excl_file = NULL;
|
||||
|
||||
cache->initialized = 0;
|
||||
}
|
||||
|
||||
int git_attr_cache__insert_macro(git_repository *repo, git_attr_rule *macro)
|
||||
{
|
||||
git_strmap *macros = git_repository_attr_cache(repo)->macros;
|
||||
int error;
|
||||
|
||||
/* TODO: generate warning log if (macro->assigns.length == 0) */
|
||||
if (macro->assigns.length == 0)
|
||||
return 0;
|
||||
|
||||
git_strmap_insert(macros, macro->match.pattern, macro, error);
|
||||
return (error < 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
git_attr_rule *git_attr_cache__lookup_macro(
|
||||
git_repository *repo, const char *name)
|
||||
{
|
||||
git_strmap *macros = git_repository_attr_cache(repo)->macros;
|
||||
khiter_t pos;
|
||||
|
||||
pos = git_strmap_lookup_index(macros, name);
|
||||
|
||||
if (!git_strmap_valid_index(macros, pos))
|
||||
return NULL;
|
||||
|
||||
return (git_attr_rule *)git_strmap_value_at(macros, pos);
|
||||
}
|
||||
|
||||
|
34
src/attr.h
34
src/attr.h
@ -8,38 +8,6 @@
|
||||
#define INCLUDE_attr_h__
|
||||
|
||||
#include "attr_file.h"
|
||||
|
||||
#define GIT_ATTR_CONFIG "core.attributesfile"
|
||||
#define GIT_IGNORE_CONFIG "core.excludesfile"
|
||||
|
||||
typedef int (*git_attr_file_parser)(
|
||||
git_repository *, void *, const char *, git_attr_file *);
|
||||
|
||||
extern int git_attr_cache__insert_macro(
|
||||
git_repository *repo, git_attr_rule *macro);
|
||||
|
||||
extern git_attr_rule *git_attr_cache__lookup_macro(
|
||||
git_repository *repo, const char *name);
|
||||
|
||||
extern int git_attr_cache__push_file(
|
||||
git_repository *repo,
|
||||
const char *base,
|
||||
const char *filename,
|
||||
git_attr_file_source source,
|
||||
git_attr_file_parser parse,
|
||||
void *parsedata, /* passed through to parse function */
|
||||
git_vector *stack);
|
||||
|
||||
extern int git_attr_cache__internal_file(
|
||||
git_repository *repo,
|
||||
const char *key,
|
||||
git_attr_file **file_ptr);
|
||||
|
||||
/* returns true if path is in cache */
|
||||
extern bool git_attr_cache__is_cached(
|
||||
git_repository *repo, git_attr_file_source source, const char *path);
|
||||
|
||||
extern int git_attr_cache__decide_sources(
|
||||
uint32_t flags, bool has_wd, bool has_index, git_attr_file_source *srcs);
|
||||
#include "attrcache.h"
|
||||
|
||||
#endif
|
||||
|
453
src/attr_file.c
453
src/attr_file.c
@ -1,11 +1,210 @@
|
||||
#include "common.h"
|
||||
#include "repository.h"
|
||||
#include "filebuf.h"
|
||||
#include "attr.h"
|
||||
#include "attr_file.h"
|
||||
#include "attrcache.h"
|
||||
#include "git2/blob.h"
|
||||
#include "git2/tree.h"
|
||||
#include "index.h"
|
||||
#include <ctype.h>
|
||||
|
||||
static void attr_file_free(git_attr_file *file)
|
||||
{
|
||||
bool unlock = !git_mutex_lock(&file->lock);
|
||||
git_attr_file__clear_rules(file, false);
|
||||
git_pool_clear(&file->pool);
|
||||
if (unlock)
|
||||
git_mutex_unlock(&file->lock);
|
||||
git_mutex_free(&file->lock);
|
||||
|
||||
git__memzero(file, sizeof(*file));
|
||||
git__free(file);
|
||||
}
|
||||
|
||||
int git_attr_file__new(
|
||||
git_attr_file **out,
|
||||
git_attr_file_entry *entry,
|
||||
git_attr_file_source source)
|
||||
{
|
||||
git_attr_file *attrs = git__calloc(1, sizeof(git_attr_file));
|
||||
GITERR_CHECK_ALLOC(attrs);
|
||||
|
||||
if (git_mutex_init(&attrs->lock) < 0) {
|
||||
giterr_set(GITERR_OS, "Failed to initialize lock");
|
||||
git__free(attrs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (git_pool_init(&attrs->pool, 1, 0) < 0) {
|
||||
attr_file_free(attrs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
GIT_REFCOUNT_INC(attrs);
|
||||
attrs->entry = entry;
|
||||
attrs->source = source;
|
||||
*out = attrs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_attr_file__clear_rules(git_attr_file *file, bool need_lock)
|
||||
{
|
||||
unsigned int i;
|
||||
git_attr_rule *rule;
|
||||
|
||||
if (need_lock && git_mutex_lock(&file->lock) < 0) {
|
||||
giterr_set(GITERR_OS, "Failed to lock attribute file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
git_vector_foreach(&file->rules, i, rule)
|
||||
git_attr_rule__free(rule);
|
||||
git_vector_free(&file->rules);
|
||||
|
||||
if (need_lock)
|
||||
git_mutex_unlock(&file->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void git_attr_file__free(git_attr_file *file)
|
||||
{
|
||||
if (!file)
|
||||
return;
|
||||
GIT_REFCOUNT_DEC(file, attr_file_free);
|
||||
}
|
||||
|
||||
static int attr_file_oid_from_index(
|
||||
git_oid *oid, git_repository *repo, const char *path)
|
||||
{
|
||||
int error;
|
||||
git_index *idx;
|
||||
size_t pos;
|
||||
const git_index_entry *entry;
|
||||
|
||||
if ((error = git_repository_index__weakptr(&idx, repo)) < 0 ||
|
||||
(error = git_index__find_pos(&pos, idx, path, 0, 0)) < 0)
|
||||
return error;
|
||||
|
||||
if (!(entry = git_index_get_byindex(idx, pos)))
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
*oid = entry->id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_attr_file__load(
|
||||
git_attr_file **out,
|
||||
git_repository *repo,
|
||||
git_attr_file_entry *entry,
|
||||
git_attr_file_source source,
|
||||
git_attr_file_parser parser)
|
||||
{
|
||||
int error = 0;
|
||||
git_blob *blob = NULL;
|
||||
git_buf content = GIT_BUF_INIT;
|
||||
const char *data = NULL;
|
||||
git_attr_file *file;
|
||||
struct stat st;
|
||||
|
||||
*out = NULL;
|
||||
|
||||
switch (source) {
|
||||
case GIT_ATTR_FILE__IN_MEMORY:
|
||||
/* in-memory attribute file doesn't need data */
|
||||
break;
|
||||
case GIT_ATTR_FILE__FROM_INDEX: {
|
||||
git_oid id;
|
||||
|
||||
if ((error = attr_file_oid_from_index(&id, repo, entry->path)) < 0 ||
|
||||
(error = git_blob_lookup(&blob, repo, &id)) < 0)
|
||||
return error;
|
||||
|
||||
data = git_blob_rawcontent(blob);
|
||||
break;
|
||||
}
|
||||
case GIT_ATTR_FILE__FROM_FILE: {
|
||||
int fd;
|
||||
|
||||
if (p_stat(entry->fullpath, &st) < 0)
|
||||
return git_path_set_error(errno, entry->fullpath, "stat");
|
||||
if (S_ISDIR(st.st_mode))
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
/* For open or read errors, return ENOTFOUND to skip item */
|
||||
/* TODO: issue warning when warning API is available */
|
||||
|
||||
if ((fd = git_futils_open_ro(entry->fullpath)) < 0)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
error = git_futils_readbuffer_fd(&content, fd, (size_t)st.st_size);
|
||||
p_close(fd);
|
||||
|
||||
if (error < 0)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
data = content.ptr;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
giterr_set(GITERR_INVALID, "Unknown file source %d", source);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((error = git_attr_file__new(&file, entry, source)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (parser && (error = parser(repo, file, data)) < 0) {
|
||||
git_attr_file__free(file);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* write cache breaker */
|
||||
if (source == GIT_ATTR_FILE__FROM_INDEX)
|
||||
git_oid_cpy(&file->cache_data.oid, git_blob_id(blob));
|
||||
else if (source == GIT_ATTR_FILE__FROM_FILE)
|
||||
git_futils_filestamp_set_from_stat(&file->cache_data.stamp, &st);
|
||||
/* else always cacheable */
|
||||
|
||||
*out = file;
|
||||
|
||||
cleanup:
|
||||
git_blob_free(blob);
|
||||
git_buf_free(&content);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_attr_file__out_of_date(git_repository *repo, git_attr_file *file)
|
||||
{
|
||||
if (!file)
|
||||
return 1;
|
||||
|
||||
switch (file->source) {
|
||||
case GIT_ATTR_FILE__IN_MEMORY:
|
||||
return 0;
|
||||
|
||||
case GIT_ATTR_FILE__FROM_FILE:
|
||||
return git_futils_filestamp_check(
|
||||
&file->cache_data.stamp, file->entry->fullpath);
|
||||
|
||||
case GIT_ATTR_FILE__FROM_INDEX: {
|
||||
int error;
|
||||
git_oid id;
|
||||
|
||||
if ((error = attr_file_oid_from_index(
|
||||
&id, repo, file->entry->path)) < 0)
|
||||
return error;
|
||||
|
||||
return (git_oid__cmp(&file->cache_data.oid, &id) != 0);
|
||||
}
|
||||
|
||||
default:
|
||||
giterr_set(GITERR_INVALID, "Invalid file type %d", file->source);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int sort_by_hash_and_name(const void *a_raw, const void *b_raw);
|
||||
static void git_attr_rule__clear(git_attr_rule *rule);
|
||||
static bool parse_optimized_patterns(
|
||||
@ -13,91 +212,42 @@ static bool parse_optimized_patterns(
|
||||
git_pool *pool,
|
||||
const char *pattern);
|
||||
|
||||
int git_attr_file__new(
|
||||
git_attr_file **attrs_ptr,
|
||||
git_attr_file_source from,
|
||||
const char *path,
|
||||
git_pool *pool)
|
||||
{
|
||||
git_attr_file *attrs = NULL;
|
||||
|
||||
attrs = git__calloc(1, sizeof(git_attr_file));
|
||||
GITERR_CHECK_ALLOC(attrs);
|
||||
|
||||
if (pool)
|
||||
attrs->pool = pool;
|
||||
else {
|
||||
attrs->pool = git__calloc(1, sizeof(git_pool));
|
||||
if (!attrs->pool || git_pool_init(attrs->pool, 1, 0) < 0)
|
||||
goto fail;
|
||||
attrs->pool_is_allocated = true;
|
||||
}
|
||||
|
||||
if (path) {
|
||||
size_t len = strlen(path);
|
||||
|
||||
attrs->key = git_pool_malloc(attrs->pool, (uint32_t)len + 3);
|
||||
GITERR_CHECK_ALLOC(attrs->key);
|
||||
|
||||
attrs->key[0] = '0' + (char)from;
|
||||
attrs->key[1] = '#';
|
||||
memcpy(&attrs->key[2], path, len);
|
||||
attrs->key[len + 2] = '\0';
|
||||
}
|
||||
|
||||
if (git_vector_init(&attrs->rules, 4, NULL) < 0)
|
||||
goto fail;
|
||||
|
||||
*attrs_ptr = attrs;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
git_attr_file__free(attrs);
|
||||
attrs_ptr = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int git_attr_file__parse_buffer(
|
||||
git_repository *repo, void *parsedata, const char *buffer, git_attr_file *attrs)
|
||||
git_repository *repo, git_attr_file *attrs, const char *data)
|
||||
{
|
||||
int error = 0;
|
||||
const char *scan = NULL;
|
||||
char *context = NULL;
|
||||
const char *scan = data, *context = NULL;
|
||||
git_attr_rule *rule = NULL;
|
||||
|
||||
GIT_UNUSED(parsedata);
|
||||
|
||||
assert(buffer && attrs);
|
||||
|
||||
scan = buffer;
|
||||
|
||||
/* if subdir file path, convert context for file paths */
|
||||
if (attrs->key && git__suffixcmp(attrs->key, "/" GIT_ATTR_FILE) == 0) {
|
||||
context = attrs->key + 2;
|
||||
context[strlen(context) - strlen(GIT_ATTR_FILE)] = '\0';
|
||||
if (attrs->entry &&
|
||||
git_path_root(attrs->entry->path) < 0 &&
|
||||
!git__suffixcmp(attrs->entry->path, "/" GIT_ATTR_FILE))
|
||||
context = attrs->entry->path;
|
||||
|
||||
if (git_mutex_lock(&attrs->lock) < 0) {
|
||||
giterr_set(GITERR_OS, "Failed to lock attribute file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (!error && *scan) {
|
||||
/* allocate rule if needed */
|
||||
if (!rule) {
|
||||
if (!(rule = git__calloc(1, sizeof(git_attr_rule)))) {
|
||||
error = -1;
|
||||
break;
|
||||
}
|
||||
rule->match.flags = GIT_ATTR_FNMATCH_ALLOWNEG |
|
||||
GIT_ATTR_FNMATCH_ALLOWMACRO;
|
||||
if (!rule && !(rule = git__calloc(1, sizeof(*rule)))) {
|
||||
error = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
rule->match.flags =
|
||||
GIT_ATTR_FNMATCH_ALLOWNEG | GIT_ATTR_FNMATCH_ALLOWMACRO;
|
||||
|
||||
/* parse the next "pattern attr attr attr" line */
|
||||
if (!(error = git_attr_fnmatch__parse(
|
||||
&rule->match, attrs->pool, context, &scan)) &&
|
||||
&rule->match, &attrs->pool, context, &scan)) &&
|
||||
!(error = git_attr_assignment__parse(
|
||||
repo, attrs->pool, &rule->assigns, &scan)))
|
||||
repo, &attrs->pool, &rule->assigns, &scan)))
|
||||
{
|
||||
if (rule->match.flags & GIT_ATTR_FNMATCH_MACRO)
|
||||
/* should generate error/warning if this is coming from any
|
||||
* file other than .gitattributes at repo root.
|
||||
*/
|
||||
/* TODO: warning if macro found in file below repo root */
|
||||
error = git_attr_cache__insert_macro(repo, rule);
|
||||
else
|
||||
error = git_vector_insert(&attrs->rules, rule);
|
||||
@ -113,66 +263,12 @@ int git_attr_file__parse_buffer(
|
||||
}
|
||||
}
|
||||
|
||||
git_mutex_unlock(&attrs->lock);
|
||||
git_attr_rule__free(rule);
|
||||
|
||||
/* restore file path used for context */
|
||||
if (context)
|
||||
context[strlen(context)] = '.'; /* first char of GIT_ATTR_FILE */
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_attr_file__new_and_load(
|
||||
git_attr_file **attrs_ptr,
|
||||
const char *path)
|
||||
{
|
||||
int error;
|
||||
git_buf content = GIT_BUF_INIT;
|
||||
|
||||
if ((error = git_attr_file__new(attrs_ptr, 0, path, NULL)) < 0)
|
||||
return error;
|
||||
|
||||
if (!(error = git_futils_readbuffer(&content, path)))
|
||||
error = git_attr_file__parse_buffer(
|
||||
NULL, NULL, git_buf_cstr(&content), *attrs_ptr);
|
||||
|
||||
git_buf_free(&content);
|
||||
|
||||
if (error) {
|
||||
git_attr_file__free(*attrs_ptr);
|
||||
*attrs_ptr = NULL;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void git_attr_file__clear_rules(git_attr_file *file)
|
||||
{
|
||||
unsigned int i;
|
||||
git_attr_rule *rule;
|
||||
|
||||
git_vector_foreach(&file->rules, i, rule)
|
||||
git_attr_rule__free(rule);
|
||||
|
||||
git_vector_free(&file->rules);
|
||||
}
|
||||
|
||||
void git_attr_file__free(git_attr_file *file)
|
||||
{
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
git_attr_file__clear_rules(file);
|
||||
|
||||
if (file->pool_is_allocated) {
|
||||
git_pool_clear(file->pool);
|
||||
git__free(file->pool);
|
||||
}
|
||||
file->pool = NULL;
|
||||
|
||||
git__free(file);
|
||||
}
|
||||
|
||||
uint32_t git_attr_file__name_hash(const char *name)
|
||||
{
|
||||
uint32_t h = 5381;
|
||||
@ -183,10 +279,9 @@ uint32_t git_attr_file__name_hash(const char *name)
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
int git_attr_file__lookup_one(
|
||||
git_attr_file *file,
|
||||
const git_attr_path *path,
|
||||
git_attr_path *path,
|
||||
const char *attr,
|
||||
const char **value)
|
||||
{
|
||||
@ -212,30 +307,83 @@ int git_attr_file__lookup_one(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_attr_file__load_standalone(git_attr_file **out, const char *path)
|
||||
{
|
||||
int error;
|
||||
git_attr_file *file;
|
||||
git_buf content = GIT_BUF_INIT;
|
||||
|
||||
error = git_attr_file__new(&file, NULL, GIT_ATTR_FILE__FROM_FILE);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
error = git_attr_cache__alloc_file_entry(
|
||||
&file->entry, NULL, path, &file->pool);
|
||||
if (error < 0) {
|
||||
git_attr_file__free(file);
|
||||
return error;
|
||||
}
|
||||
/* because the cache entry is allocated from the file's own pool, we
|
||||
* don't have to free it - freeing file+pool will free cache entry, too.
|
||||
*/
|
||||
|
||||
if (!(error = git_futils_readbuffer(&content, path))) {
|
||||
error = git_attr_file__parse_buffer(NULL, file, content.ptr);
|
||||
git_buf_free(&content);
|
||||
}
|
||||
|
||||
if (error < 0)
|
||||
git_attr_file__free(file);
|
||||
else
|
||||
*out = file;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
bool git_attr_fnmatch__match(
|
||||
git_attr_fnmatch *match,
|
||||
const git_attr_path *path)
|
||||
git_attr_path *path)
|
||||
{
|
||||
int fnm;
|
||||
int icase_flags = (match->flags & GIT_ATTR_FNMATCH_ICASE) ? FNM_CASEFOLD : 0;
|
||||
const char *filename;
|
||||
int flags = 0;
|
||||
|
||||
if (match->flags & GIT_ATTR_FNMATCH_DIRECTORY && !path->is_dir)
|
||||
return false;
|
||||
if (match->flags & GIT_ATTR_FNMATCH_ICASE)
|
||||
flags |= FNM_CASEFOLD;
|
||||
if (match->flags & GIT_ATTR_FNMATCH_LEADINGDIR)
|
||||
flags |= FNM_LEADING_DIR;
|
||||
|
||||
if (match->flags & GIT_ATTR_FNMATCH_FULLPATH)
|
||||
fnm = p_fnmatch(match->pattern, path->path, FNM_PATHNAME | icase_flags);
|
||||
else if (path->is_dir)
|
||||
fnm = p_fnmatch(match->pattern, path->basename, FNM_LEADING_DIR | icase_flags);
|
||||
else
|
||||
fnm = p_fnmatch(match->pattern, path->basename, icase_flags);
|
||||
if (match->flags & GIT_ATTR_FNMATCH_FULLPATH) {
|
||||
filename = path->path;
|
||||
flags |= FNM_PATHNAME;
|
||||
} else {
|
||||
filename = path->basename;
|
||||
|
||||
return (fnm == FNM_NOMATCH) ? false : true;
|
||||
if (path->is_dir)
|
||||
flags |= FNM_LEADING_DIR;
|
||||
}
|
||||
|
||||
if ((match->flags & GIT_ATTR_FNMATCH_DIRECTORY) && !path->is_dir) {
|
||||
int matchval;
|
||||
|
||||
/* for attribute checks or root ignore checks, fail match */
|
||||
if (!(match->flags & GIT_ATTR_FNMATCH_IGNORE) ||
|
||||
path->basename == path->path)
|
||||
return false;
|
||||
|
||||
/* for ignore checks, use container of current item for check */
|
||||
path->basename[-1] = '\0';
|
||||
flags |= FNM_LEADING_DIR;
|
||||
matchval = p_fnmatch(match->pattern, path->path, flags);
|
||||
path->basename[-1] = '/';
|
||||
return (matchval != FNM_NOMATCH);
|
||||
}
|
||||
|
||||
return (p_fnmatch(match->pattern, filename, flags) != FNM_NOMATCH);
|
||||
}
|
||||
|
||||
bool git_attr_rule__match(
|
||||
git_attr_rule *rule,
|
||||
const git_attr_path *path)
|
||||
git_attr_path *path)
|
||||
{
|
||||
bool matched = git_attr_fnmatch__match(&rule->match, path);
|
||||
|
||||
@ -245,7 +393,6 @@ bool git_attr_rule__match(
|
||||
return matched;
|
||||
}
|
||||
|
||||
|
||||
git_attr_assignment *git_attr_rule__lookup_assignment(
|
||||
git_attr_rule *rule, const char *name)
|
||||
{
|
||||
@ -344,7 +491,7 @@ void git_attr_path__free(git_attr_path *info)
|
||||
int git_attr_fnmatch__parse(
|
||||
git_attr_fnmatch *spec,
|
||||
git_pool *pool,
|
||||
const char *source,
|
||||
const char *context,
|
||||
const char **base)
|
||||
{
|
||||
const char *pattern, *scan;
|
||||
@ -410,20 +557,31 @@ int git_attr_fnmatch__parse(
|
||||
if (--slash_count <= 0)
|
||||
spec->flags = spec->flags & ~GIT_ATTR_FNMATCH_FULLPATH;
|
||||
}
|
||||
if ((spec->flags & GIT_ATTR_FNMATCH_NOLEADINGDIR) == 0 &&
|
||||
spec->length >= 2 &&
|
||||
pattern[spec->length - 1] == '*' &&
|
||||
pattern[spec->length - 2] == '/') {
|
||||
spec->length -= 2;
|
||||
spec->flags = spec->flags | GIT_ATTR_FNMATCH_LEADINGDIR;
|
||||
/* leave FULLPATH match on, however */
|
||||
}
|
||||
|
||||
if ((spec->flags & GIT_ATTR_FNMATCH_FULLPATH) != 0 &&
|
||||
source != NULL && git_path_root(pattern) < 0)
|
||||
context != NULL && git_path_root(pattern) < 0)
|
||||
{
|
||||
size_t sourcelen = strlen(source);
|
||||
/* use context path minus the trailing filename */
|
||||
char *slash = strrchr(context, '/');
|
||||
size_t contextlen = slash ? slash - context + 1 : 0;
|
||||
|
||||
/* given an unrooted fullpath match from a file inside a repo,
|
||||
* prefix the pattern with the relative directory of the source file
|
||||
*/
|
||||
spec->pattern = git_pool_malloc(
|
||||
pool, (uint32_t)(sourcelen + spec->length + 1));
|
||||
pool, (uint32_t)(contextlen + spec->length + 1));
|
||||
if (spec->pattern) {
|
||||
memcpy(spec->pattern, source, sourcelen);
|
||||
memcpy(spec->pattern + sourcelen, pattern, spec->length);
|
||||
spec->length += sourcelen;
|
||||
memcpy(spec->pattern, context, contextlen);
|
||||
memcpy(spec->pattern + contextlen, pattern, spec->length);
|
||||
spec->length += contextlen;
|
||||
spec->pattern[spec->length] = '\0';
|
||||
}
|
||||
} else {
|
||||
@ -436,6 +594,7 @@ int git_attr_fnmatch__parse(
|
||||
} else {
|
||||
/* strip '\' that might have be used for internal whitespace */
|
||||
spec->length = git__unescape(spec->pattern);
|
||||
/* TODO: convert remaining '\' into '/' for POSIX ??? */
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -30,10 +30,20 @@
|
||||
#define GIT_ATTR_FNMATCH_MATCH_ALL (1U << 8)
|
||||
#define GIT_ATTR_FNMATCH_ALLOWNEG (1U << 9)
|
||||
#define GIT_ATTR_FNMATCH_ALLOWMACRO (1U << 10)
|
||||
#define GIT_ATTR_FNMATCH_LEADINGDIR (1U << 11)
|
||||
#define GIT_ATTR_FNMATCH_NOLEADINGDIR (1U << 12)
|
||||
|
||||
#define GIT_ATTR_FNMATCH__INCOMING \
|
||||
(GIT_ATTR_FNMATCH_ALLOWSPACE | \
|
||||
GIT_ATTR_FNMATCH_ALLOWNEG | GIT_ATTR_FNMATCH_ALLOWMACRO)
|
||||
(GIT_ATTR_FNMATCH_ALLOWSPACE | GIT_ATTR_FNMATCH_ALLOWNEG | \
|
||||
GIT_ATTR_FNMATCH_ALLOWMACRO | GIT_ATTR_FNMATCH_NOLEADINGDIR)
|
||||
|
||||
typedef enum {
|
||||
GIT_ATTR_FILE__IN_MEMORY = 0,
|
||||
GIT_ATTR_FILE__FROM_FILE = 1,
|
||||
GIT_ATTR_FILE__FROM_INDEX = 2,
|
||||
|
||||
GIT_ATTR_FILE_NUM_SOURCES = 3
|
||||
} git_attr_file_source;
|
||||
|
||||
extern const char *git_attr__true;
|
||||
extern const char *git_attr__false;
|
||||
@ -63,17 +73,32 @@ typedef struct {
|
||||
const char *value;
|
||||
} git_attr_assignment;
|
||||
|
||||
typedef struct git_attr_file_entry git_attr_file_entry;
|
||||
|
||||
typedef struct {
|
||||
char *key; /* cache "source#path" this was loaded from */
|
||||
git_vector rules; /* vector of <rule*> or <fnmatch*> */
|
||||
git_pool *pool;
|
||||
bool pool_is_allocated;
|
||||
git_refcount rc;
|
||||
git_mutex lock;
|
||||
git_attr_file_entry *entry;
|
||||
git_attr_file_source source;
|
||||
git_vector rules; /* vector of <rule*> or <fnmatch*> */
|
||||
git_pool pool;
|
||||
union {
|
||||
git_oid oid;
|
||||
git_futils_filestamp stamp;
|
||||
} cache_data;
|
||||
} git_attr_file;
|
||||
|
||||
struct git_attr_file_entry {
|
||||
git_attr_file *file[GIT_ATTR_FILE_NUM_SOURCES];
|
||||
const char *path; /* points into fullpath */
|
||||
char fullpath[GIT_FLEX_ARRAY];
|
||||
};
|
||||
|
||||
typedef int (*git_attr_file_parser)(
|
||||
git_repository *repo,
|
||||
git_attr_file *file,
|
||||
const char *data);
|
||||
|
||||
typedef struct {
|
||||
git_buf full;
|
||||
char *path;
|
||||
@ -81,31 +106,39 @@ typedef struct {
|
||||
int is_dir;
|
||||
} git_attr_path;
|
||||
|
||||
typedef enum {
|
||||
GIT_ATTR_FILE_FROM_FILE = 0,
|
||||
GIT_ATTR_FILE_FROM_INDEX = 1
|
||||
} git_attr_file_source;
|
||||
|
||||
/*
|
||||
* git_attr_file API
|
||||
*/
|
||||
|
||||
extern int git_attr_file__new(
|
||||
git_attr_file **attrs_ptr, git_attr_file_source src, const char *path, git_pool *pool);
|
||||
int git_attr_file__new(
|
||||
git_attr_file **out,
|
||||
git_attr_file_entry *entry,
|
||||
git_attr_file_source source);
|
||||
|
||||
extern int git_attr_file__new_and_load(
|
||||
git_attr_file **attrs_ptr, const char *path);
|
||||
void git_attr_file__free(git_attr_file *file);
|
||||
|
||||
extern void git_attr_file__free(git_attr_file *file);
|
||||
int git_attr_file__load(
|
||||
git_attr_file **out,
|
||||
git_repository *repo,
|
||||
git_attr_file_entry *ce,
|
||||
git_attr_file_source source,
|
||||
git_attr_file_parser parser);
|
||||
|
||||
extern void git_attr_file__clear_rules(git_attr_file *file);
|
||||
int git_attr_file__load_standalone(
|
||||
git_attr_file **out, const char *path);
|
||||
|
||||
extern int git_attr_file__parse_buffer(
|
||||
git_repository *repo, void *parsedata, const char *buf, git_attr_file *file);
|
||||
int git_attr_file__out_of_date(
|
||||
git_repository *repo, git_attr_file *file);
|
||||
|
||||
extern int git_attr_file__lookup_one(
|
||||
int git_attr_file__parse_buffer(
|
||||
git_repository *repo, git_attr_file *attrs, const char *data);
|
||||
|
||||
int git_attr_file__clear_rules(
|
||||
git_attr_file *file, bool need_lock);
|
||||
|
||||
int git_attr_file__lookup_one(
|
||||
git_attr_file *file,
|
||||
const git_attr_path *path,
|
||||
git_attr_path *path,
|
||||
const char *attr,
|
||||
const char **value);
|
||||
|
||||
@ -114,7 +147,7 @@ extern int git_attr_file__lookup_one(
|
||||
git_vector_rforeach(&(file)->rules, (iter), (rule)) \
|
||||
if (git_attr_rule__match((rule), (path)))
|
||||
|
||||
extern uint32_t git_attr_file__name_hash(const char *name);
|
||||
uint32_t git_attr_file__name_hash(const char *name);
|
||||
|
||||
|
||||
/*
|
||||
@ -129,13 +162,13 @@ extern int git_attr_fnmatch__parse(
|
||||
|
||||
extern bool git_attr_fnmatch__match(
|
||||
git_attr_fnmatch *rule,
|
||||
const git_attr_path *path);
|
||||
git_attr_path *path);
|
||||
|
||||
extern void git_attr_rule__free(git_attr_rule *rule);
|
||||
|
||||
extern bool git_attr_rule__match(
|
||||
git_attr_rule *rule,
|
||||
const git_attr_path *path);
|
||||
git_attr_path *path);
|
||||
|
||||
extern git_attr_assignment *git_attr_rule__lookup_assignment(
|
||||
git_attr_rule *rule, const char *name);
|
||||
|
449
src/attrcache.c
Normal file
449
src/attrcache.c
Normal file
@ -0,0 +1,449 @@
|
||||
#include "common.h"
|
||||
#include "repository.h"
|
||||
#include "attr_file.h"
|
||||
#include "config.h"
|
||||
#include "sysdir.h"
|
||||
#include "ignore.h"
|
||||
|
||||
GIT__USE_STRMAP;
|
||||
|
||||
GIT_INLINE(int) attr_cache_lock(git_attr_cache *cache)
|
||||
{
|
||||
GIT_UNUSED(cache); /* avoid warning if threading is off */
|
||||
|
||||
if (git_mutex_lock(&cache->lock) < 0) {
|
||||
giterr_set(GITERR_OS, "Unable to get attr cache lock");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
GIT_INLINE(void) attr_cache_unlock(git_attr_cache *cache)
|
||||
{
|
||||
GIT_UNUSED(cache); /* avoid warning if threading is off */
|
||||
git_mutex_unlock(&cache->lock);
|
||||
}
|
||||
|
||||
GIT_INLINE(git_attr_file_entry *) attr_cache_lookup_entry(
|
||||
git_attr_cache *cache, const char *path)
|
||||
{
|
||||
khiter_t pos = git_strmap_lookup_index(cache->files, path);
|
||||
|
||||
if (git_strmap_valid_index(cache->files, pos))
|
||||
return git_strmap_value_at(cache->files, pos);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int git_attr_cache__alloc_file_entry(
|
||||
git_attr_file_entry **out,
|
||||
const char *base,
|
||||
const char *path,
|
||||
git_pool *pool)
|
||||
{
|
||||
size_t baselen = 0, pathlen = strlen(path);
|
||||
size_t cachesize = sizeof(git_attr_file_entry) + pathlen + 1;
|
||||
git_attr_file_entry *ce;
|
||||
|
||||
if (base != NULL && git_path_root(path) < 0) {
|
||||
baselen = strlen(base);
|
||||
cachesize += baselen;
|
||||
|
||||
if (baselen && base[baselen - 1] != '/')
|
||||
cachesize++;
|
||||
}
|
||||
|
||||
ce = git_pool_mallocz(pool, (uint32_t)cachesize);
|
||||
GITERR_CHECK_ALLOC(ce);
|
||||
|
||||
if (baselen) {
|
||||
memcpy(ce->fullpath, base, baselen);
|
||||
|
||||
if (base[baselen - 1] != '/')
|
||||
ce->fullpath[baselen++] = '/';
|
||||
}
|
||||
memcpy(&ce->fullpath[baselen], path, pathlen);
|
||||
|
||||
ce->path = &ce->fullpath[baselen];
|
||||
*out = ce;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* call with attrcache locked */
|
||||
static int attr_cache_make_entry(
|
||||
git_attr_file_entry **out, git_repository *repo, const char *path)
|
||||
{
|
||||
int error = 0;
|
||||
git_attr_cache *cache = git_repository_attr_cache(repo);
|
||||
git_attr_file_entry *entry = NULL;
|
||||
|
||||
error = git_attr_cache__alloc_file_entry(
|
||||
&entry, git_repository_workdir(repo), path, &cache->pool);
|
||||
|
||||
if (!error) {
|
||||
git_strmap_insert(cache->files, entry->path, entry, error);
|
||||
if (error > 0)
|
||||
error = 0;
|
||||
}
|
||||
|
||||
*out = entry;
|
||||
return error;
|
||||
}
|
||||
|
||||
/* insert entry or replace existing if we raced with another thread */
|
||||
static int attr_cache_upsert(git_attr_cache *cache, git_attr_file *file)
|
||||
{
|
||||
git_attr_file_entry *entry;
|
||||
git_attr_file *old;
|
||||
|
||||
if (attr_cache_lock(cache) < 0)
|
||||
return -1;
|
||||
|
||||
entry = attr_cache_lookup_entry(cache, file->entry->path);
|
||||
|
||||
GIT_REFCOUNT_OWN(file, entry);
|
||||
GIT_REFCOUNT_INC(file);
|
||||
|
||||
old = git__compare_and_swap(
|
||||
&entry->file[file->source], entry->file[file->source], file);
|
||||
|
||||
if (old) {
|
||||
GIT_REFCOUNT_OWN(old, NULL);
|
||||
git_attr_file__free(old);
|
||||
}
|
||||
|
||||
attr_cache_unlock(cache);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int attr_cache_remove(git_attr_cache *cache, git_attr_file *file)
|
||||
{
|
||||
int error = 0;
|
||||
git_attr_file_entry *entry;
|
||||
|
||||
if (!file)
|
||||
return 0;
|
||||
if ((error = attr_cache_lock(cache)) < 0)
|
||||
return error;
|
||||
|
||||
if ((entry = attr_cache_lookup_entry(cache, file->entry->path)) != NULL)
|
||||
file = git__compare_and_swap(&entry->file[file->source], file, NULL);
|
||||
|
||||
attr_cache_unlock(cache);
|
||||
|
||||
if (file) {
|
||||
GIT_REFCOUNT_OWN(file, NULL);
|
||||
git_attr_file__free(file);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Look up cache entry and file.
|
||||
* - If entry is not present, create it while the cache is locked.
|
||||
* - If file is present, increment refcount before returning it, so the
|
||||
* cache can be unlocked and it won't go away.
|
||||
*/
|
||||
static int attr_cache_lookup(
|
||||
git_attr_file **out_file,
|
||||
git_attr_file_entry **out_entry,
|
||||
git_repository *repo,
|
||||
git_attr_file_source source,
|
||||
const char *base,
|
||||
const char *filename)
|
||||
{
|
||||
int error = 0;
|
||||
git_buf path = GIT_BUF_INIT;
|
||||
const char *wd = git_repository_workdir(repo), *relfile;
|
||||
git_attr_cache *cache = git_repository_attr_cache(repo);
|
||||
git_attr_file_entry *entry = NULL;
|
||||
git_attr_file *file = NULL;
|
||||
|
||||
/* join base and path as needed */
|
||||
if (base != NULL && git_path_root(filename) < 0) {
|
||||
if (git_buf_joinpath(&path, base, filename) < 0)
|
||||
return -1;
|
||||
filename = path.ptr;
|
||||
}
|
||||
|
||||
relfile = filename;
|
||||
if (wd && !git__prefixcmp(relfile, wd))
|
||||
relfile += strlen(wd);
|
||||
|
||||
/* check cache for existing entry */
|
||||
if ((error = attr_cache_lock(cache)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
entry = attr_cache_lookup_entry(cache, relfile);
|
||||
if (!entry)
|
||||
error = attr_cache_make_entry(&entry, repo, relfile);
|
||||
else if (entry->file[source] != NULL) {
|
||||
file = entry->file[source];
|
||||
GIT_REFCOUNT_INC(file);
|
||||
}
|
||||
|
||||
attr_cache_unlock(cache);
|
||||
|
||||
cleanup:
|
||||
*out_file = file;
|
||||
*out_entry = entry;
|
||||
|
||||
git_buf_free(&path);
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_attr_cache__get(
|
||||
git_attr_file **out,
|
||||
git_repository *repo,
|
||||
git_attr_file_source source,
|
||||
const char *base,
|
||||
const char *filename,
|
||||
git_attr_file_parser parser)
|
||||
{
|
||||
int error = 0;
|
||||
git_attr_cache *cache = git_repository_attr_cache(repo);
|
||||
git_attr_file_entry *entry = NULL;
|
||||
git_attr_file *file = NULL, *updated = NULL;
|
||||
|
||||
if ((error = attr_cache_lookup(
|
||||
&file, &entry, repo, source, base, filename)) < 0)
|
||||
return error;
|
||||
|
||||
/* load file if we don't have one or if existing one is out of date */
|
||||
if (!file || (error = git_attr_file__out_of_date(repo, file)) > 0)
|
||||
error = git_attr_file__load(&updated, repo, entry, source, parser);
|
||||
|
||||
/* if we loaded the file, insert into and/or update cache */
|
||||
if (updated) {
|
||||
if ((error = attr_cache_upsert(cache, updated)) < 0)
|
||||
git_attr_file__free(updated);
|
||||
else {
|
||||
git_attr_file__free(file); /* offset incref from lookup */
|
||||
file = updated;
|
||||
}
|
||||
}
|
||||
|
||||
/* if file could not be loaded */
|
||||
if (error < 0) {
|
||||
/* remove existing entry */
|
||||
if (file) {
|
||||
attr_cache_remove(cache, file);
|
||||
git_attr_file__free(file); /* offset incref from lookup */
|
||||
file = NULL;
|
||||
}
|
||||
/* no error if file simply doesn't exist */
|
||||
if (error == GIT_ENOTFOUND) {
|
||||
giterr_clear();
|
||||
error = 0;
|
||||
}
|
||||
}
|
||||
|
||||
*out = file;
|
||||
return error;
|
||||
}
|
||||
|
||||
bool git_attr_cache__is_cached(
|
||||
git_repository *repo,
|
||||
git_attr_file_source source,
|
||||
const char *filename)
|
||||
{
|
||||
git_attr_cache *cache = git_repository_attr_cache(repo);
|
||||
git_strmap *files;
|
||||
khiter_t pos;
|
||||
git_attr_file_entry *entry;
|
||||
|
||||
if (!cache || !(files = cache->files))
|
||||
return false;
|
||||
|
||||
pos = git_strmap_lookup_index(files, filename);
|
||||
if (!git_strmap_valid_index(files, pos))
|
||||
return false;
|
||||
|
||||
entry = git_strmap_value_at(files, pos);
|
||||
|
||||
return entry && (entry->file[source] != NULL);
|
||||
}
|
||||
|
||||
|
||||
static int attr_cache__lookup_path(
|
||||
char **out, git_config *cfg, const char *key, const char *fallback)
|
||||
{
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
int error;
|
||||
const git_config_entry *entry = NULL;
|
||||
|
||||
*out = NULL;
|
||||
|
||||
if ((error = git_config__lookup_entry(&entry, cfg, key, false)) < 0)
|
||||
return error;
|
||||
|
||||
if (entry) {
|
||||
const char *cfgval = entry->value;
|
||||
|
||||
/* expand leading ~/ as needed */
|
||||
if (cfgval && cfgval[0] == '~' && cfgval[1] == '/' &&
|
||||
!git_sysdir_find_global_file(&buf, &cfgval[2]))
|
||||
*out = git_buf_detach(&buf);
|
||||
else if (cfgval)
|
||||
*out = git__strdup(cfgval);
|
||||
}
|
||||
else if (!git_sysdir_find_xdg_file(&buf, fallback))
|
||||
*out = git_buf_detach(&buf);
|
||||
|
||||
git_buf_free(&buf);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static void attr_cache__free(git_attr_cache *cache)
|
||||
{
|
||||
bool unlock;
|
||||
|
||||
if (!cache)
|
||||
return;
|
||||
|
||||
unlock = (git_mutex_lock(&cache->lock) == 0);
|
||||
|
||||
if (cache->files != NULL) {
|
||||
git_attr_file_entry *entry;
|
||||
git_attr_file *file;
|
||||
int i;
|
||||
|
||||
git_strmap_foreach_value(cache->files, entry, {
|
||||
for (i = 0; i < GIT_ATTR_FILE_NUM_SOURCES; ++i) {
|
||||
if ((file = git__swap(entry->file[i], NULL)) != NULL) {
|
||||
GIT_REFCOUNT_OWN(file, NULL);
|
||||
git_attr_file__free(file);
|
||||
}
|
||||
}
|
||||
});
|
||||
git_strmap_free(cache->files);
|
||||
}
|
||||
|
||||
if (cache->macros != NULL) {
|
||||
git_attr_rule *rule;
|
||||
|
||||
git_strmap_foreach_value(cache->macros, rule, {
|
||||
git_attr_rule__free(rule);
|
||||
});
|
||||
git_strmap_free(cache->macros);
|
||||
}
|
||||
|
||||
git_pool_clear(&cache->pool);
|
||||
|
||||
git__free(cache->cfg_attr_file);
|
||||
cache->cfg_attr_file = NULL;
|
||||
|
||||
git__free(cache->cfg_excl_file);
|
||||
cache->cfg_excl_file = NULL;
|
||||
|
||||
if (unlock)
|
||||
git_mutex_unlock(&cache->lock);
|
||||
git_mutex_free(&cache->lock);
|
||||
|
||||
git__free(cache);
|
||||
}
|
||||
|
||||
int git_attr_cache__do_init(git_repository *repo)
|
||||
{
|
||||
int ret = 0;
|
||||
git_attr_cache *cache = git_repository_attr_cache(repo);
|
||||
git_config *cfg = NULL;
|
||||
|
||||
if (cache)
|
||||
return 0;
|
||||
|
||||
cache = git__calloc(1, sizeof(git_attr_cache));
|
||||
GITERR_CHECK_ALLOC(cache);
|
||||
|
||||
/* set up lock */
|
||||
if (git_mutex_init(&cache->lock) < 0) {
|
||||
giterr_set(GITERR_OS, "Unable to initialize lock for attr cache");
|
||||
git__free(cache);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ret = git_repository_config_snapshot(&cfg, repo)) < 0)
|
||||
goto cancel;
|
||||
|
||||
/* cache config settings for attributes and ignores */
|
||||
ret = attr_cache__lookup_path(
|
||||
&cache->cfg_attr_file, cfg, GIT_ATTR_CONFIG, GIT_ATTR_FILE_XDG);
|
||||
if (ret < 0)
|
||||
goto cancel;
|
||||
|
||||
ret = attr_cache__lookup_path(
|
||||
&cache->cfg_excl_file, cfg, GIT_IGNORE_CONFIG, GIT_IGNORE_FILE_XDG);
|
||||
if (ret < 0)
|
||||
goto cancel;
|
||||
|
||||
/* allocate hashtable for attribute and ignore file contents,
|
||||
* hashtable for attribute macros, and string pool
|
||||
*/
|
||||
if ((ret = git_strmap_alloc(&cache->files)) < 0 ||
|
||||
(ret = git_strmap_alloc(&cache->macros)) < 0 ||
|
||||
(ret = git_pool_init(&cache->pool, 1, 0)) < 0)
|
||||
goto cancel;
|
||||
|
||||
cache = git__compare_and_swap(&repo->attrcache, NULL, cache);
|
||||
if (cache)
|
||||
goto cancel; /* raced with another thread, free this but no error */
|
||||
|
||||
git_config_free(cfg);
|
||||
|
||||
/* insert default macros */
|
||||
return git_attr_add_macro(repo, "binary", "-diff -crlf -text");
|
||||
|
||||
cancel:
|
||||
attr_cache__free(cache);
|
||||
git_config_free(cfg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void git_attr_cache_flush(git_repository *repo)
|
||||
{
|
||||
git_attr_cache *cache;
|
||||
|
||||
/* this could be done less expensively, but for now, we'll just free
|
||||
* the entire attrcache and let the next use reinitialize it...
|
||||
*/
|
||||
if (repo && (cache = git__swap(repo->attrcache, NULL)) != NULL)
|
||||
attr_cache__free(cache);
|
||||
}
|
||||
|
||||
int git_attr_cache__insert_macro(git_repository *repo, git_attr_rule *macro)
|
||||
{
|
||||
git_attr_cache *cache = git_repository_attr_cache(repo);
|
||||
git_strmap *macros = cache->macros;
|
||||
int error;
|
||||
|
||||
/* TODO: generate warning log if (macro->assigns.length == 0) */
|
||||
if (macro->assigns.length == 0)
|
||||
return 0;
|
||||
|
||||
if (git_mutex_lock(&cache->lock) < 0) {
|
||||
giterr_set(GITERR_OS, "Unable to get attr cache lock");
|
||||
error = -1;
|
||||
} else {
|
||||
git_strmap_insert(macros, macro->match.pattern, macro, error);
|
||||
git_mutex_unlock(&cache->lock);
|
||||
}
|
||||
|
||||
return (error < 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
git_attr_rule *git_attr_cache__lookup_macro(
|
||||
git_repository *repo, const char *name)
|
||||
{
|
||||
git_strmap *macros = git_repository_attr_cache(repo)->macros;
|
||||
khiter_t pos;
|
||||
|
||||
pos = git_strmap_lookup_index(macros, name);
|
||||
|
||||
if (!git_strmap_valid_index(macros, pos))
|
||||
return NULL;
|
||||
|
||||
return (git_attr_rule *)git_strmap_value_at(macros, pos);
|
||||
}
|
||||
|
@ -7,18 +7,50 @@
|
||||
#ifndef INCLUDE_attrcache_h__
|
||||
#define INCLUDE_attrcache_h__
|
||||
|
||||
#include "pool.h"
|
||||
#include "attr_file.h"
|
||||
#include "strmap.h"
|
||||
|
||||
#define GIT_ATTR_CONFIG "core.attributesfile"
|
||||
#define GIT_IGNORE_CONFIG "core.excludesfile"
|
||||
|
||||
typedef struct {
|
||||
int initialized;
|
||||
git_pool pool;
|
||||
git_strmap *files; /* hash path to git_attr_file of rules */
|
||||
git_strmap *macros; /* hash name to vector<git_attr_assignment> */
|
||||
char *cfg_attr_file; /* cached value of core.attributesfile */
|
||||
char *cfg_excl_file; /* cached value of core.excludesfile */
|
||||
git_strmap *files; /* hash path to git_attr_cache_entry records */
|
||||
git_strmap *macros; /* hash name to vector<git_attr_assignment> */
|
||||
git_mutex lock;
|
||||
git_pool pool;
|
||||
} git_attr_cache;
|
||||
|
||||
extern int git_attr_cache__init(git_repository *repo);
|
||||
extern int git_attr_cache__do_init(git_repository *repo);
|
||||
|
||||
#define git_attr_cache__init(REPO) \
|
||||
(git_repository_attr_cache(REPO) ? 0 : git_attr_cache__do_init(REPO))
|
||||
|
||||
/* get file - loading and reload as needed */
|
||||
extern int git_attr_cache__get(
|
||||
git_attr_file **file,
|
||||
git_repository *repo,
|
||||
git_attr_file_source source,
|
||||
const char *base,
|
||||
const char *filename,
|
||||
git_attr_file_parser parser);
|
||||
|
||||
extern bool git_attr_cache__is_cached(
|
||||
git_repository *repo,
|
||||
git_attr_file_source source,
|
||||
const char *path);
|
||||
|
||||
extern int git_attr_cache__alloc_file_entry(
|
||||
git_attr_file_entry **out,
|
||||
const char *base,
|
||||
const char *path,
|
||||
git_pool *pool);
|
||||
|
||||
extern int git_attr_cache__insert_macro(
|
||||
git_repository *repo, git_attr_rule *macro);
|
||||
|
||||
extern git_attr_rule *git_attr_cache__lookup_macro(
|
||||
git_repository *repo, const char *name);
|
||||
|
||||
#endif
|
||||
|
@ -7,7 +7,7 @@
|
||||
#ifndef INCLUDE_bitvec_h__
|
||||
#define INCLUDE_bitvec_h__
|
||||
|
||||
#include "util.h"
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* This is a silly little fixed length bit vector type that will store
|
||||
|
66
src/blame.c
66
src/blame.c
@ -20,12 +20,15 @@
|
||||
|
||||
static int hunk_byfinalline_search_cmp(const void *key, const void *entry)
|
||||
{
|
||||
uint16_t lineno = (uint16_t)*(size_t*)key;
|
||||
git_blame_hunk *hunk = (git_blame_hunk*)entry;
|
||||
|
||||
if (lineno < hunk->final_start_line_number)
|
||||
size_t lineno = *(size_t*)key;
|
||||
size_t lines_in_hunk = (size_t)hunk->lines_in_hunk;
|
||||
size_t final_start_line_number = (size_t)hunk->final_start_line_number;
|
||||
|
||||
if (lineno < final_start_line_number)
|
||||
return -1;
|
||||
if (lineno >= hunk->final_start_line_number + hunk->lines_in_hunk)
|
||||
if (lineno >= final_start_line_number + lines_in_hunk)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@ -76,8 +79,8 @@ static git_blame_hunk* dup_hunk(git_blame_hunk *hunk)
|
||||
git_oid_cpy(&newhunk->orig_commit_id, &hunk->orig_commit_id);
|
||||
git_oid_cpy(&newhunk->final_commit_id, &hunk->final_commit_id);
|
||||
newhunk->boundary = hunk->boundary;
|
||||
newhunk->final_signature = git_signature_dup(hunk->final_signature);
|
||||
newhunk->orig_signature = git_signature_dup(hunk->orig_signature);
|
||||
git_signature_dup(&newhunk->final_signature, hunk->final_signature);
|
||||
git_signature_dup(&newhunk->orig_signature, hunk->orig_signature);
|
||||
return newhunk;
|
||||
}
|
||||
|
||||
@ -95,7 +98,7 @@ static void shift_hunks_by(git_vector *v, size_t start_line, int shift_by)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!git_vector_bsearch2( &i, v, hunk_byfinalline_search_cmp, &start_line)) {
|
||||
if (!git_vector_bsearch2(&i, v, hunk_byfinalline_search_cmp, &start_line)) {
|
||||
for (; i < v->length; i++) {
|
||||
git_blame_hunk *hunk = (git_blame_hunk*)v->contents[i];
|
||||
hunk->final_start_line_number += shift_by;
|
||||
@ -108,17 +111,22 @@ git_blame* git_blame__alloc(
|
||||
git_blame_options opts,
|
||||
const char *path)
|
||||
{
|
||||
git_blame *gbr = (git_blame*)git__calloc(1, sizeof(git_blame));
|
||||
if (!gbr) {
|
||||
giterr_set_oom();
|
||||
git_blame *gbr = git__calloc(1, sizeof(git_blame));
|
||||
if (!gbr)
|
||||
return NULL;
|
||||
}
|
||||
git_vector_init(&gbr->hunks, 8, hunk_cmp);
|
||||
git_vector_init(&gbr->paths, 8, paths_cmp);
|
||||
|
||||
gbr->repository = repo;
|
||||
gbr->options = opts;
|
||||
gbr->path = git__strdup(path);
|
||||
git_vector_insert(&gbr->paths, git__strdup(path));
|
||||
|
||||
if (git_vector_init(&gbr->hunks, 8, hunk_cmp) < 0 ||
|
||||
git_vector_init(&gbr->paths, 8, paths_cmp) < 0 ||
|
||||
(gbr->path = git__strdup(path)) == NULL ||
|
||||
git_vector_insert(&gbr->paths, git__strdup(path)) < 0)
|
||||
{
|
||||
git_blame_free(gbr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return gbr;
|
||||
}
|
||||
|
||||
@ -126,7 +134,6 @@ void git_blame_free(git_blame *blame)
|
||||
{
|
||||
size_t i;
|
||||
git_blame_hunk *hunk;
|
||||
char *path;
|
||||
|
||||
if (!blame) return;
|
||||
|
||||
@ -134,13 +141,11 @@ void git_blame_free(git_blame *blame)
|
||||
free_hunk(hunk);
|
||||
git_vector_free(&blame->hunks);
|
||||
|
||||
git_vector_foreach(&blame->paths, i, path)
|
||||
git__free(path);
|
||||
git_vector_free(&blame->paths);
|
||||
git_vector_free_deep(&blame->paths);
|
||||
|
||||
git_array_clear(blame->line_index);
|
||||
|
||||
git__free((void*)blame->path);
|
||||
git__free(blame->path);
|
||||
git_blob_free(blame->final_blob);
|
||||
git__free(blame);
|
||||
}
|
||||
@ -159,10 +164,10 @@ const git_blame_hunk *git_blame_get_hunk_byindex(git_blame *blame, uint32_t inde
|
||||
|
||||
const git_blame_hunk *git_blame_get_hunk_byline(git_blame *blame, uint32_t lineno)
|
||||
{
|
||||
size_t i;
|
||||
size_t i, new_lineno = (size_t)lineno;
|
||||
assert(blame);
|
||||
|
||||
if (!git_vector_bsearch2( &i, &blame->hunks, hunk_byfinalline_search_cmp, &lineno)) {
|
||||
if (!git_vector_bsearch2(&i, &blame->hunks, hunk_byfinalline_search_cmp, &new_lineno)) {
|
||||
return git_blame_get_hunk_byindex(blame, (uint32_t)i);
|
||||
}
|
||||
|
||||
@ -239,7 +244,7 @@ static int index_blob_lines(git_blame *blame)
|
||||
git_off_t len = blame->final_buf_size;
|
||||
int num = 0, incomplete = 0, bol = 1;
|
||||
size_t *i;
|
||||
|
||||
|
||||
if (len && buf[len-1] != '\n')
|
||||
incomplete++; /* incomplete line at the end */
|
||||
while (len--) {
|
||||
@ -260,13 +265,15 @@ static int index_blob_lines(git_blame *blame)
|
||||
blame->num_lines = num + incomplete;
|
||||
return blame->num_lines;
|
||||
}
|
||||
|
||||
|
||||
static git_blame_hunk* hunk_from_entry(git_blame__entry *e)
|
||||
{
|
||||
git_blame_hunk *h = new_hunk(
|
||||
e->lno+1, e->num_lines, e->s_lno+1, e->suspect->path);
|
||||
git_oid_cpy(&h->final_commit_id, git_commit_id(e->suspect->commit));
|
||||
h->final_signature = git_signature_dup(git_commit_author(e->suspect->commit));
|
||||
git_oid_cpy(&h->orig_commit_id, git_commit_id(e->suspect->commit));
|
||||
git_signature_dup(&h->final_signature, git_commit_author(e->suspect->commit));
|
||||
git_signature_dup(&h->orig_signature, git_commit_author(e->suspect->commit));
|
||||
h->boundary = e->is_boundary ? 1 : 0;
|
||||
return h;
|
||||
}
|
||||
@ -282,8 +289,6 @@ static int load_blob(git_blame *blame)
|
||||
goto cleanup;
|
||||
error = git_object_lookup_bypath((git_object**)&blame->final_blob,
|
||||
(git_object*)blame->final, blame->path, GIT_OBJ_BLOB);
|
||||
if (error < 0)
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
return error;
|
||||
@ -448,7 +453,7 @@ int git_blame_buffer(
|
||||
git_blame **out,
|
||||
git_blame *reference,
|
||||
const char *buffer,
|
||||
uint32_t buffer_len)
|
||||
size_t buffer_len)
|
||||
{
|
||||
git_blame *blame;
|
||||
git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT;
|
||||
@ -474,3 +479,10 @@ int git_blame_buffer(
|
||||
*out = blame;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_blame_init_options(git_blame_options *opts, unsigned int version)
|
||||
{
|
||||
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
|
||||
opts, version, git_blame_options, GIT_BLAME_OPTIONS_INIT);
|
||||
return 0;
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ typedef struct git_blame__entry {
|
||||
} git_blame__entry;
|
||||
|
||||
struct git_blame {
|
||||
const char *path;
|
||||
char *path;
|
||||
git_repository *repository;
|
||||
git_blame_options options;
|
||||
|
||||
|
@ -485,12 +485,14 @@ static void pass_blame(git_blame *blame, git_blame__origin *origin, uint32_t opt
|
||||
git_blame__origin *sg_buf[16];
|
||||
git_blame__origin *porigin, **sg_origin = sg_buf;
|
||||
|
||||
GIT_UNUSED(opt);
|
||||
|
||||
num_parents = git_commit_parentcount(commit);
|
||||
if (!git_oid_cmp(git_commit_id(commit), &blame->options.oldest_commit))
|
||||
/* Stop at oldest specified commit */
|
||||
num_parents = 0;
|
||||
else if (opt & GIT_BLAME_FIRST_PARENT && num_parents > 1)
|
||||
/* Limit search to the first parent */
|
||||
num_parents = 1;
|
||||
|
||||
if (!num_parents) {
|
||||
git_oid_cpy(&blame->options.oldest_commit, git_commit_id(commit));
|
||||
goto finish;
|
||||
|
86
src/blob.c
86
src/blob.c
@ -50,25 +50,28 @@ int git_blob__parse(void *blob, git_odb_object *odb_obj)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *buffer, size_t len)
|
||||
int git_blob_create_frombuffer(
|
||||
git_oid *id, git_repository *repo, const void *buffer, size_t len)
|
||||
{
|
||||
int error;
|
||||
git_odb *odb;
|
||||
git_odb_stream *stream;
|
||||
|
||||
assert(id && repo);
|
||||
|
||||
if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 ||
|
||||
(error = git_odb_open_wstream(&stream, odb, len, GIT_OBJ_BLOB)) < 0)
|
||||
return error;
|
||||
|
||||
if ((error = git_odb_stream_write(stream, buffer, len)) == 0)
|
||||
error = git_odb_stream_finalize_write(oid, stream);
|
||||
error = git_odb_stream_finalize_write(id, stream);
|
||||
|
||||
git_odb_stream_free(stream);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int write_file_stream(
|
||||
git_oid *oid, git_odb *odb, const char *path, git_off_t file_size)
|
||||
git_oid *id, git_odb *odb, const char *path, git_off_t file_size)
|
||||
{
|
||||
int fd, error;
|
||||
char buffer[4096];
|
||||
@ -97,14 +100,14 @@ static int write_file_stream(
|
||||
}
|
||||
|
||||
if (!error)
|
||||
error = git_odb_stream_finalize_write(oid, stream);
|
||||
error = git_odb_stream_finalize_write(id, stream);
|
||||
|
||||
git_odb_stream_free(stream);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int write_file_filtered(
|
||||
git_oid *oid,
|
||||
git_oid *id,
|
||||
git_off_t *size,
|
||||
git_odb *odb,
|
||||
const char *full_path,
|
||||
@ -119,7 +122,7 @@ static int write_file_filtered(
|
||||
if (!error) {
|
||||
*size = tgt.size;
|
||||
|
||||
error = git_odb_write(oid, odb, tgt.ptr, tgt.size, GIT_OBJ_BLOB);
|
||||
error = git_odb_write(id, odb, tgt.ptr, tgt.size, GIT_OBJ_BLOB);
|
||||
}
|
||||
|
||||
git_buf_free(&tgt);
|
||||
@ -127,7 +130,7 @@ static int write_file_filtered(
|
||||
}
|
||||
|
||||
static int write_symlink(
|
||||
git_oid *oid, git_odb *odb, const char *path, size_t link_size)
|
||||
git_oid *id, git_odb *odb, const char *path, size_t link_size)
|
||||
{
|
||||
char *link_data;
|
||||
ssize_t read_len;
|
||||
@ -143,13 +146,13 @@ static int write_symlink(
|
||||
return -1;
|
||||
}
|
||||
|
||||
error = git_odb_write(oid, odb, (void *)link_data, link_size, GIT_OBJ_BLOB);
|
||||
error = git_odb_write(id, odb, (void *)link_data, link_size, GIT_OBJ_BLOB);
|
||||
git__free(link_data);
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_blob__create_from_paths(
|
||||
git_oid *oid,
|
||||
git_oid *id,
|
||||
struct stat *out_st,
|
||||
git_repository *repo,
|
||||
const char *content_path,
|
||||
@ -188,24 +191,25 @@ int git_blob__create_from_paths(
|
||||
mode = hint_mode ? hint_mode : st.st_mode;
|
||||
|
||||
if (S_ISLNK(mode)) {
|
||||
error = write_symlink(oid, odb, content_path, (size_t)size);
|
||||
error = write_symlink(id, odb, content_path, (size_t)size);
|
||||
} else {
|
||||
git_filter_list *fl = NULL;
|
||||
|
||||
if (try_load_filters)
|
||||
/* Load the filters for writing this file to the ODB */
|
||||
error = git_filter_list_load(
|
||||
&fl, repo, NULL, hint_path, GIT_FILTER_TO_ODB);
|
||||
&fl, repo, NULL, hint_path,
|
||||
GIT_FILTER_TO_ODB, GIT_FILTER_OPT_DEFAULT);
|
||||
|
||||
if (error < 0)
|
||||
/* well, that didn't work */;
|
||||
else if (fl == NULL)
|
||||
/* No filters need to be applied to the document: we can stream
|
||||
* directly from disk */
|
||||
error = write_file_stream(oid, odb, content_path, size);
|
||||
error = write_file_stream(id, odb, content_path, size);
|
||||
else {
|
||||
/* We need to apply one or more filters */
|
||||
error = write_file_filtered(oid, &size, odb, content_path, fl);
|
||||
error = write_file_filtered(id, &size, odb, content_path, fl);
|
||||
|
||||
git_filter_list_free(fl);
|
||||
}
|
||||
@ -233,13 +237,13 @@ done:
|
||||
}
|
||||
|
||||
int git_blob_create_fromworkdir(
|
||||
git_oid *oid, git_repository *repo, const char *path)
|
||||
git_oid *id, git_repository *repo, const char *path)
|
||||
{
|
||||
return git_blob__create_from_paths(oid, NULL, repo, NULL, path, 0, true);
|
||||
return git_blob__create_from_paths(id, NULL, repo, NULL, path, 0, true);
|
||||
}
|
||||
|
||||
int git_blob_create_fromdisk(
|
||||
git_oid *oid, git_repository *repo, const char *path)
|
||||
git_oid *id, git_repository *repo, const char *path)
|
||||
{
|
||||
int error;
|
||||
git_buf full_path = GIT_BUF_INIT;
|
||||
@ -257,7 +261,7 @@ int git_blob_create_fromdisk(
|
||||
hintpath += strlen(workdir);
|
||||
|
||||
error = git_blob__create_from_paths(
|
||||
oid, NULL, repo, git_buf_cstr(&full_path), hintpath, 0, true);
|
||||
id, NULL, repo, git_buf_cstr(&full_path), hintpath, 0, true);
|
||||
|
||||
git_buf_free(&full_path);
|
||||
return error;
|
||||
@ -266,63 +270,72 @@ int git_blob_create_fromdisk(
|
||||
#define BUFFER_SIZE 4096
|
||||
|
||||
int git_blob_create_fromchunks(
|
||||
git_oid *oid,
|
||||
git_oid *id,
|
||||
git_repository *repo,
|
||||
const char *hintpath,
|
||||
int (*source_cb)(char *content, size_t max_length, void *payload),
|
||||
void *payload)
|
||||
{
|
||||
int error = -1, read_bytes;
|
||||
int error;
|
||||
char *content = NULL;
|
||||
git_filebuf file = GIT_FILEBUF_INIT;
|
||||
git_buf path = GIT_BUF_INIT;
|
||||
|
||||
if (git_buf_joinpath(
|
||||
&path, git_repository_path(repo), GIT_OBJECTS_DIR "streamed") < 0)
|
||||
assert(id && repo && source_cb);
|
||||
|
||||
if ((error = git_buf_joinpath(
|
||||
&path, git_repository_path(repo), GIT_OBJECTS_DIR "streamed")) < 0)
|
||||
goto cleanup;
|
||||
|
||||
content = git__malloc(BUFFER_SIZE);
|
||||
GITERR_CHECK_ALLOC(content);
|
||||
|
||||
if (git_filebuf_open(&file, git_buf_cstr(&path), GIT_FILEBUF_TEMPORARY, 0666) < 0)
|
||||
if ((error = git_filebuf_open(
|
||||
&file, git_buf_cstr(&path), GIT_FILEBUF_TEMPORARY, 0666)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
while (1) {
|
||||
read_bytes = source_cb(content, BUFFER_SIZE, payload);
|
||||
int read_bytes = source_cb(content, BUFFER_SIZE, payload);
|
||||
|
||||
assert(read_bytes <= BUFFER_SIZE);
|
||||
|
||||
if (read_bytes <= 0)
|
||||
if (!read_bytes)
|
||||
break;
|
||||
|
||||
if (git_filebuf_write(&file, content, read_bytes) < 0)
|
||||
if (read_bytes > BUFFER_SIZE) {
|
||||
giterr_set(GITERR_OBJECT, "Invalid chunk size while creating blob");
|
||||
error = GIT_EBUFS;
|
||||
} else if (read_bytes < 0) {
|
||||
error = giterr_set_after_callback(read_bytes);
|
||||
} else {
|
||||
error = git_filebuf_write(&file, content, read_bytes);
|
||||
}
|
||||
|
||||
if (error < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (read_bytes < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_filebuf_flush(&file) < 0)
|
||||
if ((error = git_filebuf_flush(&file)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
error = git_blob__create_from_paths(
|
||||
oid, NULL, repo, file.path_lock, hintpath, 0, hintpath != NULL);
|
||||
id, NULL, repo, file.path_lock, hintpath, 0, hintpath != NULL);
|
||||
|
||||
cleanup:
|
||||
git_buf_free(&path);
|
||||
git_filebuf_cleanup(&file);
|
||||
git__free(content);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_blob_is_binary(git_blob *blob)
|
||||
int git_blob_is_binary(const git_blob *blob)
|
||||
{
|
||||
git_buf content;
|
||||
|
||||
assert(blob);
|
||||
|
||||
content.ptr = blob->odb_object->buffer;
|
||||
content.size = min(blob->odb_object->cached.size, 4000);
|
||||
content.size =
|
||||
min(blob->odb_object->cached.size, GIT_FILTER_BYTES_TO_CHECK_NUL);
|
||||
content.asize = 0;
|
||||
|
||||
return git_buf_text_is_binary(&content);
|
||||
@ -339,11 +352,14 @@ int git_blob_filtered_content(
|
||||
|
||||
assert(blob && path && out);
|
||||
|
||||
git_buf_sanitize(out);
|
||||
|
||||
if (check_for_binary_data && git_blob_is_binary(blob))
|
||||
return 0;
|
||||
|
||||
if (!(error = git_filter_list_load(
|
||||
&fl, git_blob_owner(blob), blob, path, GIT_FILTER_TO_WORKTREE))) {
|
||||
&fl, git_blob_owner(blob), blob, path,
|
||||
GIT_FILTER_TO_WORKTREE, GIT_FILTER_OPT_DEFAULT))) {
|
||||
|
||||
error = git_filter_list_apply_to_blob(out, fl, blob);
|
||||
|
||||
|
249
src/branch.c
249
src/branch.c
@ -21,27 +21,22 @@ static int retrieve_branch_reference(
|
||||
const char *branch_name,
|
||||
int is_remote)
|
||||
{
|
||||
git_reference *branch;
|
||||
int error = -1;
|
||||
git_reference *branch = NULL;
|
||||
int error = 0;
|
||||
char *prefix;
|
||||
git_buf ref_name = GIT_BUF_INIT;
|
||||
|
||||
*branch_reference_out = NULL;
|
||||
|
||||
prefix = is_remote ? GIT_REFS_REMOTES_DIR : GIT_REFS_HEADS_DIR;
|
||||
|
||||
if (git_buf_joinpath(&ref_name, prefix, branch_name) < 0)
|
||||
goto cleanup;
|
||||
if ((error = git_buf_joinpath(&ref_name, prefix, branch_name)) < 0)
|
||||
/* OOM */;
|
||||
else if ((error = git_reference_lookup(&branch, repo, ref_name.ptr)) < 0)
|
||||
giterr_set(
|
||||
GITERR_REFERENCE, "Cannot locate %s branch '%s'",
|
||||
is_remote ? "remote-tracking" : "local", branch_name);
|
||||
|
||||
if ((error = git_reference_lookup(&branch, repo, ref_name.ptr)) < 0) {
|
||||
giterr_set(GITERR_REFERENCE,
|
||||
"Cannot locate %s branch '%s'.", is_remote ? "remote-tracking" : "local", branch_name);
|
||||
goto cleanup;
|
||||
}
|
||||
*branch_reference_out = branch; /* will be NULL on error */
|
||||
|
||||
*branch_reference_out = branch;
|
||||
|
||||
cleanup:
|
||||
git_buf_free(&ref_name);
|
||||
return error;
|
||||
}
|
||||
@ -59,26 +54,53 @@ int git_branch_create(
|
||||
git_repository *repository,
|
||||
const char *branch_name,
|
||||
const git_commit *commit,
|
||||
int force)
|
||||
int force,
|
||||
const git_signature *signature,
|
||||
const char *log_message)
|
||||
{
|
||||
int is_head = 0;
|
||||
git_reference *branch = NULL;
|
||||
git_buf canonical_branch_name = GIT_BUF_INIT;
|
||||
git_buf canonical_branch_name = GIT_BUF_INIT,
|
||||
log_message_buf = GIT_BUF_INIT;
|
||||
int error = -1;
|
||||
|
||||
assert(branch_name && commit && ref_out);
|
||||
assert(git_object_owner((const git_object *)commit) == repository);
|
||||
|
||||
if (force && git_branch_lookup(&branch, repository, branch_name, GIT_BRANCH_LOCAL) == 0) {
|
||||
error = git_branch_is_head(branch);
|
||||
git_reference_free(branch);
|
||||
branch = NULL;
|
||||
|
||||
if (error < 0)
|
||||
goto cleanup;
|
||||
|
||||
is_head = error;
|
||||
}
|
||||
|
||||
if (is_head && force) {
|
||||
giterr_set(GITERR_REFERENCE, "Cannot force update branch '%s' as it is "
|
||||
"the current HEAD of the repository.", branch_name);
|
||||
error = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_buf_sets(&log_message_buf, log_message ? log_message : "Branch: created") < 0)
|
||||
goto cleanup;
|
||||
|
||||
error = git_reference_create(&branch, repository,
|
||||
git_buf_cstr(&canonical_branch_name), git_commit_id(commit), force);
|
||||
git_buf_cstr(&canonical_branch_name), git_commit_id(commit), force, signature,
|
||||
git_buf_cstr(&log_message_buf));
|
||||
|
||||
if (!error)
|
||||
*ref_out = branch;
|
||||
|
||||
cleanup:
|
||||
git_buf_free(&canonical_branch_name);
|
||||
git_buf_free(&log_message_buf);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -90,33 +112,35 @@ int git_branch_delete(git_reference *branch)
|
||||
|
||||
assert(branch);
|
||||
|
||||
if (!git_reference_is_branch(branch) &&
|
||||
!git_reference_is_remote(branch)) {
|
||||
giterr_set(GITERR_INVALID, "Reference '%s' is not a valid branch.", git_reference_name(branch));
|
||||
return -1;
|
||||
if (!git_reference_is_branch(branch) && !git_reference_is_remote(branch)) {
|
||||
giterr_set(GITERR_INVALID, "Reference '%s' is not a valid branch.",
|
||||
git_reference_name(branch));
|
||||
return GIT_ENOTFOUND;
|
||||
}
|
||||
|
||||
if ((is_head = git_branch_is_head(branch)) < 0)
|
||||
return is_head;
|
||||
|
||||
if (is_head) {
|
||||
giterr_set(GITERR_REFERENCE,
|
||||
"Cannot delete branch '%s' as it is the current HEAD of the repository.", git_reference_name(branch));
|
||||
giterr_set(GITERR_REFERENCE, "Cannot delete branch '%s' as it is "
|
||||
"the current HEAD of the repository.", git_reference_name(branch));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (git_buf_printf(&config_section, "branch.%s", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0)
|
||||
if (git_buf_join(&config_section, '.', "branch",
|
||||
git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0)
|
||||
goto on_error;
|
||||
|
||||
if (git_config_rename_section(
|
||||
git_reference_owner(branch),
|
||||
git_buf_cstr(&config_section),
|
||||
NULL) < 0)
|
||||
goto on_error;
|
||||
git_reference_owner(branch), git_buf_cstr(&config_section), NULL) < 0)
|
||||
goto on_error;
|
||||
|
||||
if (git_reference_delete(branch) < 0)
|
||||
goto on_error;
|
||||
|
||||
if (git_reflog_delete(git_reference_owner(branch), git_reference_name(branch)) < 0)
|
||||
goto on_error;
|
||||
|
||||
error = 0;
|
||||
|
||||
on_error:
|
||||
@ -182,6 +206,9 @@ void git_branch_iterator_free(git_branch_iterator *_iter)
|
||||
{
|
||||
branch_iter *iter = (branch_iter *) _iter;
|
||||
|
||||
if (iter == NULL)
|
||||
return;
|
||||
|
||||
git_reference_iterator_free(iter->iter);
|
||||
git__free(iter);
|
||||
}
|
||||
@ -190,11 +217,14 @@ int git_branch_move(
|
||||
git_reference **out,
|
||||
git_reference *branch,
|
||||
const char *new_branch_name,
|
||||
int force)
|
||||
int force,
|
||||
const git_signature *signature,
|
||||
const char *log_message)
|
||||
{
|
||||
git_buf new_reference_name = GIT_BUF_INIT,
|
||||
old_config_section = GIT_BUF_INIT,
|
||||
new_config_section = GIT_BUF_INIT;
|
||||
old_config_section = GIT_BUF_INIT,
|
||||
new_config_section = GIT_BUF_INIT,
|
||||
log_message_buf = GIT_BUF_INIT;
|
||||
int error;
|
||||
|
||||
assert(branch && new_branch_name);
|
||||
@ -202,26 +232,40 @@ int git_branch_move(
|
||||
if (!git_reference_is_branch(branch))
|
||||
return not_a_local_branch(git_reference_name(branch));
|
||||
|
||||
error = git_buf_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name);
|
||||
if ((error = git_buf_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name)) < 0)
|
||||
goto done;
|
||||
|
||||
if (log_message) {
|
||||
if ((error = git_buf_sets(&log_message_buf, log_message)) < 0)
|
||||
goto done;
|
||||
} else {
|
||||
if ((error = git_buf_printf(&log_message_buf, "Branch: renamed %s to %s",
|
||||
git_reference_name(branch), git_buf_cstr(&new_reference_name))) < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* first update ref then config so failure won't trash config */
|
||||
|
||||
error = git_reference_rename(
|
||||
out, branch, git_buf_cstr(&new_reference_name), force,
|
||||
signature, git_buf_cstr(&log_message_buf));
|
||||
if (error < 0)
|
||||
goto done;
|
||||
|
||||
git_buf_printf(&old_config_section,
|
||||
"branch.%s", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR));
|
||||
git_buf_join(&old_config_section, '.', "branch",
|
||||
git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR));
|
||||
git_buf_join(&new_config_section, '.', "branch", new_branch_name);
|
||||
|
||||
git_buf_printf(&new_config_section, "branch.%s", new_branch_name);
|
||||
|
||||
if ((error = git_config_rename_section(git_reference_owner(branch),
|
||||
error = git_config_rename_section(
|
||||
git_reference_owner(branch),
|
||||
git_buf_cstr(&old_config_section),
|
||||
git_buf_cstr(&new_config_section))) < 0)
|
||||
goto done;
|
||||
|
||||
error = git_reference_rename(out, branch, git_buf_cstr(&new_reference_name), force);
|
||||
git_buf_cstr(&new_config_section));
|
||||
|
||||
done:
|
||||
git_buf_free(&new_reference_name);
|
||||
git_buf_free(&old_config_section);
|
||||
git_buf_free(&new_config_section);
|
||||
git_buf_free(&log_message_buf);
|
||||
|
||||
return error;
|
||||
}
|
||||
@ -237,7 +281,9 @@ int git_branch_lookup(
|
||||
return retrieve_branch_reference(ref_out, repo, branch_name, branch_type == GIT_BRANCH_REMOTE);
|
||||
}
|
||||
|
||||
int git_branch_name(const char **out, git_reference *ref)
|
||||
int git_branch_name(
|
||||
const char **out,
|
||||
const git_reference *ref)
|
||||
{
|
||||
const char *branch_name;
|
||||
|
||||
@ -260,17 +306,13 @@ int git_branch_name(const char **out, git_reference *ref)
|
||||
|
||||
static int retrieve_upstream_configuration(
|
||||
const char **out,
|
||||
git_repository *repo,
|
||||
const git_config *config,
|
||||
const char *canonical_branch_name,
|
||||
const char *format)
|
||||
{
|
||||
git_config *config;
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
int error;
|
||||
|
||||
if (git_repository_config__weakptr(&config, repo) < 0)
|
||||
return -1;
|
||||
|
||||
if (git_buf_printf(&buf, format,
|
||||
canonical_branch_name + strlen(GIT_REFS_HEADS_DIR)) < 0)
|
||||
return -1;
|
||||
@ -280,33 +322,39 @@ static int retrieve_upstream_configuration(
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_branch_upstream__name(
|
||||
git_buf *tracking_name,
|
||||
int git_branch_upstream_name(
|
||||
git_buf *out,
|
||||
git_repository *repo,
|
||||
const char *canonical_branch_name)
|
||||
const char *refname)
|
||||
{
|
||||
const char *remote_name, *merge_name;
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
int error = -1;
|
||||
git_remote *remote = NULL;
|
||||
const git_refspec *refspec;
|
||||
git_config *config;
|
||||
|
||||
assert(tracking_name && canonical_branch_name);
|
||||
assert(out && refname);
|
||||
|
||||
if (!git_reference__is_branch(canonical_branch_name))
|
||||
return not_a_local_branch(canonical_branch_name);
|
||||
git_buf_sanitize(out);
|
||||
|
||||
if (!git_reference__is_branch(refname))
|
||||
return not_a_local_branch(refname);
|
||||
|
||||
if ((error = git_repository_config_snapshot(&config, repo)) < 0)
|
||||
return error;
|
||||
|
||||
if ((error = retrieve_upstream_configuration(
|
||||
&remote_name, repo, canonical_branch_name, "branch.%s.remote")) < 0)
|
||||
&remote_name, config, refname, "branch.%s.remote")) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if ((error = retrieve_upstream_configuration(
|
||||
&merge_name, repo, canonical_branch_name, "branch.%s.merge")) < 0)
|
||||
&merge_name, config, refname, "branch.%s.merge")) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (!*remote_name || !*merge_name) {
|
||||
giterr_set(GITERR_REFERENCE,
|
||||
"branch '%s' does not have an upstream", canonical_branch_name);
|
||||
"branch '%s' does not have an upstream", refname);
|
||||
error = GIT_ENOTFOUND;
|
||||
goto cleanup;
|
||||
}
|
||||
@ -321,21 +369,22 @@ int git_branch_upstream__name(
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (git_refspec_transform_r(&buf, refspec, merge_name) < 0)
|
||||
if (git_refspec_transform(&buf, refspec, merge_name) < 0)
|
||||
goto cleanup;
|
||||
} else
|
||||
if (git_buf_sets(&buf, merge_name) < 0)
|
||||
goto cleanup;
|
||||
|
||||
error = git_buf_set(tracking_name, git_buf_cstr(&buf), git_buf_len(&buf));
|
||||
error = git_buf_set(out, git_buf_cstr(&buf), git_buf_len(&buf));
|
||||
|
||||
cleanup:
|
||||
git_config_free(config);
|
||||
git_remote_free(remote);
|
||||
git_buf_free(&buf);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int remote_name(git_buf *buf, git_repository *repo, const char *canonical_branch_name)
|
||||
int git_branch_remote_name(git_buf *buf, git_repository *repo, const char *refname)
|
||||
{
|
||||
git_strarray remote_list = {0};
|
||||
size_t i;
|
||||
@ -344,12 +393,14 @@ static int remote_name(git_buf *buf, git_repository *repo, const char *canonical
|
||||
int error = 0;
|
||||
char *remote_name = NULL;
|
||||
|
||||
assert(buf && repo && canonical_branch_name);
|
||||
assert(buf && repo && refname);
|
||||
|
||||
git_buf_sanitize(buf);
|
||||
|
||||
/* Verify that this is a remote branch */
|
||||
if (!git_reference__is_remote(canonical_branch_name)) {
|
||||
if (!git_reference__is_remote(refname)) {
|
||||
giterr_set(GITERR_INVALID, "Reference '%s' is not a remote branch.",
|
||||
canonical_branch_name);
|
||||
refname);
|
||||
error = GIT_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
@ -363,7 +414,7 @@ static int remote_name(git_buf *buf, git_repository *repo, const char *canonical
|
||||
if ((error = git_remote_load(&remote, repo, remote_list.strings[i])) < 0)
|
||||
continue;
|
||||
|
||||
fetchspec = git_remote__matching_dst_refspec(remote, canonical_branch_name);
|
||||
fetchspec = git_remote__matching_dst_refspec(remote, refname);
|
||||
if (fetchspec) {
|
||||
/* If we have not already set out yet, then set
|
||||
* it to the matching remote name. Otherwise
|
||||
@ -375,7 +426,7 @@ static int remote_name(git_buf *buf, git_repository *repo, const char *canonical
|
||||
git_remote_free(remote);
|
||||
|
||||
giterr_set(GITERR_REFERENCE,
|
||||
"Reference '%s' is ambiguous", canonical_branch_name);
|
||||
"Reference '%s' is ambiguous", refname);
|
||||
error = GIT_EAMBIGUOUS;
|
||||
goto cleanup;
|
||||
}
|
||||
@ -389,76 +440,26 @@ static int remote_name(git_buf *buf, git_repository *repo, const char *canonical
|
||||
error = git_buf_puts(buf, remote_name);
|
||||
} else {
|
||||
giterr_set(GITERR_REFERENCE,
|
||||
"Could not determine remote for '%s'", canonical_branch_name);
|
||||
"Could not determine remote for '%s'", refname);
|
||||
error = GIT_ENOTFOUND;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (error < 0)
|
||||
git_buf_free(buf);
|
||||
|
||||
git_strarray_free(&remote_list);
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_branch_remote_name(char *buffer, size_t buffer_len, git_repository *repo, const char *refname)
|
||||
{
|
||||
int ret;
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
|
||||
if ((ret = remote_name(&buf, repo, refname)) < 0)
|
||||
return ret;
|
||||
|
||||
if (buffer)
|
||||
git_buf_copy_cstr(buffer, buffer_len, &buf);
|
||||
|
||||
ret = (int)git_buf_len(&buf) + 1;
|
||||
git_buf_free(&buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int git_branch_upstream_name(
|
||||
char *tracking_branch_name_out,
|
||||
size_t buffer_size,
|
||||
git_repository *repo,
|
||||
const char *canonical_branch_name)
|
||||
{
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
int error;
|
||||
|
||||
assert(canonical_branch_name);
|
||||
|
||||
if (tracking_branch_name_out && buffer_size)
|
||||
*tracking_branch_name_out = '\0';
|
||||
|
||||
if ((error = git_branch_upstream__name(
|
||||
&buf, repo, canonical_branch_name)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (tracking_branch_name_out && buf.size + 1 > buffer_size) { /* +1 for NUL byte */
|
||||
giterr_set(
|
||||
GITERR_INVALID,
|
||||
"Buffer too short to hold the tracked reference name.");
|
||||
error = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (tracking_branch_name_out)
|
||||
git_buf_copy_cstr(tracking_branch_name_out, buffer_size, &buf);
|
||||
|
||||
error = (int)buf.size + 1;
|
||||
|
||||
cleanup:
|
||||
git_buf_free(&buf);
|
||||
return (int)error;
|
||||
}
|
||||
|
||||
int git_branch_upstream(
|
||||
git_reference **tracking_out,
|
||||
git_reference *branch)
|
||||
git_reference **tracking_out,
|
||||
const git_reference *branch)
|
||||
{
|
||||
int error;
|
||||
git_buf tracking_name = GIT_BUF_INIT;
|
||||
|
||||
if ((error = git_branch_upstream__name(&tracking_name,
|
||||
if ((error = git_branch_upstream_name(&tracking_name,
|
||||
git_reference_owner(branch), git_reference_name(branch))) < 0)
|
||||
return error;
|
||||
|
||||
@ -541,7 +542,7 @@ int git_branch_set_upstream(git_reference *branch, const char *upstream_name)
|
||||
if (local)
|
||||
git_buf_puts(&value, ".");
|
||||
else
|
||||
remote_name(&value, repo, git_reference_name(upstream));
|
||||
git_branch_remote_name(&value, repo, git_reference_name(upstream));
|
||||
|
||||
if (git_buf_printf(&key, "branch.%s.remote", shortname) < 0)
|
||||
goto on_error;
|
||||
@ -560,7 +561,7 @@ int git_branch_set_upstream(git_reference *branch, const char *upstream_name)
|
||||
|
||||
fetchspec = git_remote__matching_dst_refspec(remote, git_reference_name(upstream));
|
||||
git_buf_clear(&value);
|
||||
if (!fetchspec || git_refspec_transform_l(&value, fetchspec, git_reference_name(upstream)) < 0)
|
||||
if (!fetchspec || git_refspec_rtransform(&value, fetchspec, git_reference_name(upstream)) < 0)
|
||||
goto on_error;
|
||||
|
||||
git_remote_free(remote);
|
||||
@ -590,7 +591,7 @@ on_error:
|
||||
}
|
||||
|
||||
int git_branch_is_head(
|
||||
git_reference *branch)
|
||||
const git_reference *branch)
|
||||
{
|
||||
git_reference *head;
|
||||
bool is_same = false;
|
||||
|
149
src/buffer.c
149
src/buffer.c
@ -7,7 +7,6 @@
|
||||
#include "buffer.h"
|
||||
#include "posix.h"
|
||||
#include "git2/buffer.h"
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* Used as default value for git_buf->ptr so that people can always
|
||||
@ -66,8 +65,10 @@ int git_buf_try_grow(
|
||||
new_ptr = git__realloc(new_ptr, new_size);
|
||||
|
||||
if (!new_ptr) {
|
||||
if (mark_oom)
|
||||
if (mark_oom) {
|
||||
if (buf->ptr) git__free(buf->ptr);
|
||||
buf->ptr = git_buf__oom;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -100,12 +101,23 @@ void git_buf_free(git_buf *buf)
|
||||
git_buf_init(buf, 0);
|
||||
}
|
||||
|
||||
void git_buf_sanitize(git_buf *buf)
|
||||
{
|
||||
if (buf->ptr == NULL) {
|
||||
assert(buf->size == 0 && buf->asize == 0);
|
||||
buf->ptr = git_buf__initbuf;
|
||||
} else if (buf->asize > buf->size)
|
||||
buf->ptr[buf->size] = '\0';
|
||||
}
|
||||
|
||||
void git_buf_clear(git_buf *buf)
|
||||
{
|
||||
buf->size = 0;
|
||||
|
||||
if (!buf->ptr)
|
||||
if (!buf->ptr) {
|
||||
buf->ptr = git_buf__initbuf;
|
||||
buf->asize = 0;
|
||||
}
|
||||
|
||||
if (buf->asize > 0)
|
||||
buf->ptr[0] = '\0';
|
||||
@ -120,8 +132,11 @@ int git_buf_set(git_buf *buf, const void *data, size_t len)
|
||||
ENSURE_SIZE(buf, len + 1);
|
||||
memmove(buf->ptr, data, len);
|
||||
}
|
||||
|
||||
buf->size = len;
|
||||
buf->ptr[buf->size] = '\0';
|
||||
if (buf->asize > buf->size)
|
||||
buf->ptr[buf->size] = '\0';
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -139,6 +154,15 @@ int git_buf_putc(git_buf *buf, char c)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_buf_putcn(git_buf *buf, char c, size_t len)
|
||||
{
|
||||
ENSURE_SIZE(buf, buf->size + len + 1);
|
||||
memset(buf->ptr + buf->size, c, len);
|
||||
buf->size += len;
|
||||
buf->ptr[buf->size] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_buf_put(git_buf *buf, const char *data, size_t len)
|
||||
{
|
||||
ENSURE_SIZE(buf, buf->size + len + 1);
|
||||
@ -194,6 +218,42 @@ int git_buf_put_base64(git_buf *buf, const char *data, size_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char b85str[] =
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~";
|
||||
|
||||
int git_buf_put_base85(git_buf *buf, const char *data, size_t len)
|
||||
{
|
||||
ENSURE_SIZE(buf, buf->size + (5 * ((len / 4) + !!(len % 4))) + 1);
|
||||
|
||||
while (len) {
|
||||
uint32_t acc = 0;
|
||||
char b85[5];
|
||||
int i;
|
||||
|
||||
for (i = 24; i >= 0; i -= 8) {
|
||||
uint8_t ch = *data++;
|
||||
acc |= ch << i;
|
||||
|
||||
if (--len == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 4; i >= 0; i--) {
|
||||
int val = acc % 85;
|
||||
acc /= 85;
|
||||
|
||||
b85[i] = b85str[val];
|
||||
}
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
buf->ptr[buf->size++] = b85[i];
|
||||
}
|
||||
|
||||
buf->ptr[buf->size] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_buf_vprintf(git_buf *buf, const char *format, va_list ap)
|
||||
{
|
||||
int len;
|
||||
@ -272,19 +332,20 @@ void git_buf_consume(git_buf *buf, const char *end)
|
||||
|
||||
void git_buf_truncate(git_buf *buf, size_t len)
|
||||
{
|
||||
if (len < buf->size) {
|
||||
buf->size = len;
|
||||
if (len >= buf->size)
|
||||
return;
|
||||
|
||||
buf->size = len;
|
||||
if (buf->size < buf->asize)
|
||||
buf->ptr[buf->size] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
void git_buf_shorten(git_buf *buf, size_t amount)
|
||||
{
|
||||
if (amount > buf->size)
|
||||
amount = buf->size;
|
||||
|
||||
buf->size = buf->size - amount;
|
||||
buf->ptr[buf->size] = '\0';
|
||||
if (buf->size > amount)
|
||||
git_buf_truncate(buf, buf->size - amount);
|
||||
else
|
||||
git_buf_clear(buf);
|
||||
}
|
||||
|
||||
void git_buf_rtruncate_at_char(git_buf *buf, char separator)
|
||||
@ -424,7 +485,7 @@ int git_buf_join(
|
||||
ssize_t offset_a = -1;
|
||||
|
||||
/* not safe to have str_b point internally to the buffer */
|
||||
assert(str_b < buf->ptr || str_b > buf->ptr + buf->size);
|
||||
assert(str_b < buf->ptr || str_b >= buf->ptr + buf->size);
|
||||
|
||||
/* figure out if we need to insert a separator */
|
||||
if (separator && strlen_a) {
|
||||
@ -439,13 +500,14 @@ int git_buf_join(
|
||||
|
||||
if (git_buf_grow(buf, strlen_a + strlen_b + need_sep + 1) < 0)
|
||||
return -1;
|
||||
assert(buf->ptr);
|
||||
|
||||
/* fix up internal pointers */
|
||||
if (offset_a >= 0)
|
||||
str_a = buf->ptr + offset_a;
|
||||
|
||||
/* do the actual copying */
|
||||
if (offset_a != 0)
|
||||
if (offset_a != 0 && str_a)
|
||||
memmove(buf->ptr, str_a, strlen_a);
|
||||
if (need_sep)
|
||||
buf->ptr[strlen_a] = separator;
|
||||
@ -457,6 +519,59 @@ int git_buf_join(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_buf_join3(
|
||||
git_buf *buf,
|
||||
char separator,
|
||||
const char *str_a,
|
||||
const char *str_b,
|
||||
const char *str_c)
|
||||
{
|
||||
size_t len_a = strlen(str_a), len_b = strlen(str_b), len_c = strlen(str_c);
|
||||
int sep_a = 0, sep_b = 0;
|
||||
char *tgt;
|
||||
|
||||
/* for this function, disallow pointers into the existing buffer */
|
||||
assert(str_a < buf->ptr || str_a >= buf->ptr + buf->size);
|
||||
assert(str_b < buf->ptr || str_b >= buf->ptr + buf->size);
|
||||
assert(str_c < buf->ptr || str_c >= buf->ptr + buf->size);
|
||||
|
||||
if (separator) {
|
||||
if (len_a > 0) {
|
||||
while (*str_b == separator) { str_b++; len_b--; }
|
||||
sep_a = (str_a[len_a - 1] != separator);
|
||||
}
|
||||
if (len_a > 0 || len_b > 0)
|
||||
while (*str_c == separator) { str_c++; len_c--; }
|
||||
if (len_b > 0)
|
||||
sep_b = (str_b[len_b - 1] != separator);
|
||||
}
|
||||
|
||||
if (git_buf_grow(buf, len_a + sep_a + len_b + sep_b + len_c + 1) < 0)
|
||||
return -1;
|
||||
|
||||
tgt = buf->ptr;
|
||||
|
||||
if (len_a) {
|
||||
memcpy(tgt, str_a, len_a);
|
||||
tgt += len_a;
|
||||
}
|
||||
if (sep_a)
|
||||
*tgt++ = separator;
|
||||
if (len_b) {
|
||||
memcpy(tgt, str_b, len_b);
|
||||
tgt += len_b;
|
||||
}
|
||||
if (sep_b)
|
||||
*tgt++ = separator;
|
||||
if (len_c)
|
||||
memcpy(tgt, str_c, len_c);
|
||||
|
||||
buf->size = len_a + sep_a + len_b + sep_b + len_c;
|
||||
buf->ptr[buf->size] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void git_buf_rtrim(git_buf *buf)
|
||||
{
|
||||
while (buf->size > 0) {
|
||||
@ -466,7 +581,8 @@ void git_buf_rtrim(git_buf *buf)
|
||||
buf->size--;
|
||||
}
|
||||
|
||||
buf->ptr[buf->size] = '\0';
|
||||
if (buf->asize > buf->size)
|
||||
buf->ptr[buf->size] = '\0';
|
||||
}
|
||||
|
||||
int git_buf_cmp(const git_buf *a, const git_buf *b)
|
||||
@ -490,8 +606,7 @@ int git_buf_splice(
|
||||
/* Ported from git.git
|
||||
* https://github.com/git/git/blob/16eed7c/strbuf.c#L159-176
|
||||
*/
|
||||
if (git_buf_grow(buf, git_buf_len(buf) + nb_to_insert - nb_to_remove) < 0)
|
||||
return -1;
|
||||
ENSURE_SIZE(buf, buf->size + nb_to_insert - nb_to_insert + 1);
|
||||
|
||||
memmove(buf->ptr + where + nb_to_insert,
|
||||
buf->ptr + where + nb_to_remove,
|
||||
|
18
src/buffer.h
18
src/buffer.h
@ -10,7 +10,6 @@
|
||||
#include "common.h"
|
||||
#include "git2/strarray.h"
|
||||
#include "git2/buffer.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
/* typedef struct {
|
||||
* char *ptr;
|
||||
@ -50,6 +49,15 @@ extern void git_buf_init(git_buf *buf, size_t initial_size);
|
||||
extern int git_buf_try_grow(
|
||||
git_buf *buf, size_t target_size, bool mark_oom, bool preserve_external);
|
||||
|
||||
/**
|
||||
* Sanitizes git_buf structures provided from user input. Users of the
|
||||
* library, when providing git_buf's, may wish to provide a NULL ptr for
|
||||
* ease of handling. The buffer routines, however, expect a non-NULL ptr
|
||||
* always. This helper method simply handles NULL input, converting to a
|
||||
* git_buf__initbuf.
|
||||
*/
|
||||
extern void git_buf_sanitize(git_buf *buf);
|
||||
|
||||
extern void git_buf_swap(git_buf *buf_a, git_buf *buf_b);
|
||||
extern char *git_buf_detach(git_buf *buf);
|
||||
extern void git_buf_attach(git_buf *buf, char *ptr, size_t asize);
|
||||
@ -80,6 +88,7 @@ GIT_INLINE(bool) git_buf_oom(const git_buf *buf)
|
||||
*/
|
||||
int git_buf_sets(git_buf *buf, const char *string);
|
||||
int git_buf_putc(git_buf *buf, char c);
|
||||
int git_buf_putcn(git_buf *buf, char c, size_t len);
|
||||
int git_buf_put(git_buf *buf, const char *data, size_t len);
|
||||
int git_buf_puts(git_buf *buf, const char *string);
|
||||
int git_buf_printf(git_buf *buf, const char *format, ...) GIT_FORMAT_PRINTF(2, 3);
|
||||
@ -90,8 +99,12 @@ void git_buf_truncate(git_buf *buf, size_t len);
|
||||
void git_buf_shorten(git_buf *buf, size_t amount);
|
||||
void git_buf_rtruncate_at_char(git_buf *path, char separator);
|
||||
|
||||
/** General join with separator */
|
||||
int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...);
|
||||
/** Fast join of two strings - first may legally point into `buf` data */
|
||||
int git_buf_join(git_buf *buf, char separator, const char *str_a, const char *str_b);
|
||||
/** Fast join of three strings - cannot reference `buf` data */
|
||||
int git_buf_join3(git_buf *buf, char separator, const char *str_a, const char *str_b, const char *str_c);
|
||||
|
||||
/**
|
||||
* Join two strings as paths, inserting a slash between as needed.
|
||||
@ -145,6 +158,9 @@ int git_buf_cmp(const git_buf *a, const git_buf *b);
|
||||
/* Write data as base64 encoded in buffer */
|
||||
int git_buf_put_base64(git_buf *buf, const char *data, size_t len);
|
||||
|
||||
/* Write data as "base85" encoded in buffer */
|
||||
int git_buf_put_base85(git_buf *buf, const char *data, size_t len);
|
||||
|
||||
/*
|
||||
* Insert, remove or replace a portion of the buffer.
|
||||
*
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user