Skip to content

Instantly share code, notes, and snippets.

@z80oolong
Last active May 16, 2019 09:15
Show Gist options
  • Save z80oolong/d33892b66257242b347211c944de78c8 to your computer and use it in GitHub Desktop.
Save z80oolong/d33892b66257242b347211c944de78c8 to your computer and use it in GitHub Desktop.
git 2.17.0 以降において config ファイルの lock に失敗する場合の挙動を変更する差分ファイル

git 2.17.0 以降において config ファイルの lock に失敗する場合の挙動を変更する差分ファイル

概要

分散型バージョン管理システムである git において、 VFAT ファイルシステム及び Android OS 及び Debian noroot 環境における外部ストレージ領域において、 git clone コマンド等を用いて新しい git リポジトリを作成する場合に、 .git/config ファイルの lock ファイルについて lock ファイルの権限の変更に失敗するために、 .git/config の lock に失敗し、リポジトリが作成できない問題が発生しています。

これらの差分ファイルは、 git において、前述のような .git/config ファイルの lock に失敗する場合の挙動について、 lock の失敗を無視するかどうかの git の挙動を設定する事を可能にするための差分ファイルです。

また、 git のインストール時において、ハードリンクに代えてシンボリックリンクを使用する修正も同時に加えています。

差分ファイルの適用とコンパイル

git のソースコードに差分ファイルを適用するには、安定版の git-x.y.z (ここに、x, y, z は安定版のバージョン番号。以下同様。) には、差分ファイル git-x.y.z-fix.diff を、github 上の git には、差分ファイル git-HEAD-*-fix.diff (ここに、 * は、 HEAD 版の commit 番号) をそれぞれ適用して下さい。

例えば、安定版の git-x.y.z のソースコードに git-x.y.z-fix.diff を適用するには、安定版の git-x.y.z のソースコードが置かれているディレクトリより、以下のようにして差分ファイル git-2.17.0-fix.diff を適用します。

 $ patch -p1 < /path/to/git-x.y.z-fix.diff
 (ここに、/path/to/diff は、 git-x.y.z-fix.diff が置かれたディレクトリのパス名)

なお、以下に示す差分ファイルは、それぞれ右に示す git の安定版にも適用可能です。

そして、 github 上の git のソースコードに git-HEAD-*-fix.diff を適用するには、安定版の github 上の git のソースコードが置かれているディレクトリより、以下のようにして差分ファイル git-HEAD-*-fix.diff を適用します。

 $ patch -p1 < /path/to/git-HEAD-*-fix.diff
 (ここに、/path/to/diff は、 git-HEAD-*-fix.diff が置かれたディレクトリのパス名)

差分ファイルの適用後は、以下のようにして git をコンパイル及びインストールします。

 $ make prefix=/path/to/install install CFLAGS="..." LDFLAGS="..."
 (ここに、 /path/to/install は git のインストール先のパス名であり、環境変数 CFLAGS, LDFLAGS は適切な値を設定する。)

使用法

git において、 .git/config ファイルの lock の失敗を無視するかどうかの挙動の設定については、設定項目 core.errorLevelConfigLockFailure を使用します。 core.errorLevelConfigLockFailure に設定する各設定値の意味は下記の通りです。

  • core.errorLevelConfigLockFailure = error
    通常の git の動作の通り、 lock の失敗時に異常終了します。
  • core.errorLevelConfigLockFailure = warn
    git の動作において、 .git/config ファイルの lock の失敗時に警告メッセージを表示した後、 lock の失敗を無視してリポジトリの作成等を続行します。
    設定項目 core.errorLevelConfigLockFailure のデフォルト値です。
  • core.errorLevelConfigLockFailure = quiet
    git の動作において、 .git/config ファイルの lock の失敗時に何もメッセージを表示せず、 lock の失敗を無視してリポジトリの作成等を続行します。

ここで、設定項目 core.errorLevelConfigLockFailure を変更するには下記のコマンドを実行します。

 $ git config --global core.errorLevelConfigLockFailure quiet

 (若しくは、 git config --global core.errorLevelConfigLockFailure error)
 (若しくは、 git config --global core.errorLevelConfigLockFailure warn)

なお、 設定項目 core.errorLevelConfigLockFailure については、設定ファイル $HOME/.gitignore を直接編集することでも設定できます。

謝辞

なお、これらの差分ファイルの作成に当たっては、 termux の開発コミュニティ による差分ファイルを参考にしました。 termux の開発コミュニティの皆様には心より感謝致します。

そして、 Junio C Hamano 氏を始めとした git の開発コミュニティの皆様及び git に関わる全ての方々にも心より感謝致します。

追記及び御断り

2018/07/12 現在の追記

2018/07/12 現在の git の[安定版のバージョンの 2.18.0][G180] 及び github 上の git の HEAD の commit である e3331758に対応した差分ファイルである git-2.18.0-fix.diff, git-HEAD-e3331758-fix.diff を追加致しました。

これに伴い、差分ファイル git-HEAD-6f333ff2-fix.diff を削除しました。どうか御了承下さい。

なお、これに伴い、 config ファイルの lock に失敗する場合の挙動を変更する git を導入するための Formula 群である z80oolong/git を更新しました。こちらの方もどうか御覧下さい。

2018/10/08 現在の追記

2018/07/12 現在の git の[安定版のバージョンの 2.19.0][G180] 及び github 上の git の HEAD の commit である fe8321ecに対応した差分ファイルである git-2.19.0-fix.diff, git-HEAD-fe8321ec-fix.diff を追加致しました。

これに伴い、差分ファイル git-HEAD-e3331758-fix.diff を削除しました。どうか御了承下さい。

2019/01/18 現在の追記

2019/01/18 現在の git の安定版のバージョンの 2.19.22.20.0 及び github 上の git の HEAD の commit である 77556354に対応した差分ファイルである git-2.19.2-fix.diff, git-2.20.0-fix.diff, git-HEAD-fe8321ec-fix.diff を追加致しました。

これに伴い、差分ファイル git-HEAD-fe8321ec-fix.diff を削除しました。どうか御了承下さい。

2019/03/20 現在の追記

2019/03/20 現在の git の安定版のバージョンの 2.21.0 及び github 上の git の HEAD の commit である 0e94f7aaに対応した差分ファイルである git-2.21.0-fix.diff, git-HEAD-0e94f7aa-fix.diff を追加致しました。

これに伴い、 git-2.21.0-fix.diff 以外の安定版の差分ファイル及び git-HEAD-77556354-fix.diff を削除しました。どうか御了承下さい。

diff --git a/Makefile b/Makefile
index c524094..c9429c9 100644
--- a/Makefile
+++ b/Makefile
@@ -2108,7 +2108,6 @@ version.sp version.s version.o: EXTRA_CPPFLAGS = \
$(BUILT_INS): git$X
$(QUIET_BUILT_IN)$(RM) $@ && \
- ln $< $@ 2>/dev/null || \
ln -s $< $@ 2>/dev/null || \
cp $< $@
@@ -2429,7 +2428,6 @@ git-remote-testsvn$X: remote-testsvn.o GIT-LDFLAGS $(GITLIBS) $(VCSSVN_LIB)
$(REMOTE_CURL_ALIASES): $(REMOTE_CURL_PRIMARY)
$(QUIET_LNCP)$(RM) $@ && \
- ln $< $@ 2>/dev/null || \
ln -s $< $@ 2>/dev/null || \
cp $< $@
@@ -2861,7 +2859,6 @@ endif
test -n "$(INSTALL_SYMLINKS)" && \
ln -s "$$destdir_from_execdir_SQ/$(bindir_relative_SQ)/$$p" "$$execdir/$$p" || \
{ test -z "$(NO_INSTALL_HARDLINKS)$(NO_CROSS_DIRECTORY_HARDLINKS)" && \
- ln "$$bindir/$$p" "$$execdir/$$p" 2>/dev/null || \
cp "$$bindir/$$p" "$$execdir/$$p" || exit; } \
done; \
} && \
@@ -2870,7 +2867,6 @@ endif
test -n "$(INSTALL_SYMLINKS)" && \
ln -s "git$X" "$$bindir/$$p" || \
{ test -z "$(NO_INSTALL_HARDLINKS)" && \
- ln "$$bindir/git$X" "$$bindir/$$p" 2>/dev/null || \
ln -s "git$X" "$$bindir/$$p" 2>/dev/null || \
cp "$$bindir/git$X" "$$bindir/$$p" || exit; } \
done && \
@@ -2879,7 +2875,6 @@ endif
test -n "$(INSTALL_SYMLINKS)" && \
ln -s "$$destdir_from_execdir_SQ/$(bindir_relative_SQ)/git$X" "$$execdir/$$p" || \
{ test -z "$(NO_INSTALL_HARDLINKS)" && \
- ln "$$execdir/git$X" "$$execdir/$$p" 2>/dev/null || \
ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \
cp "$$execdir/git$X" "$$execdir/$$p" || exit; } \
done && \
@@ -2889,7 +2884,6 @@ endif
test -n "$(INSTALL_SYMLINKS)" && \
ln -s "git-remote-http$X" "$$execdir/$$p" || \
{ test -z "$(NO_INSTALL_HARDLINKS)" && \
- ln "$$execdir/git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
ln -s "git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
cp "$$execdir/git-remote-http$X" "$$execdir/$$p" || exit; } \
done && \
diff --git a/config.c b/config.c
index 24ad1a9..8d052c8 100644
--- a/config.c
+++ b/config.c
@@ -77,6 +77,53 @@ static int core_compression_seen;
static int pack_compression_seen;
static int zlib_compression_seen;
+#ifndef NO_USE_ERRLEVEL_CONFIG_LOCK_FAILURE
+/*
+ * If the git configuration file (.git/config) cannot be locked on a shared
+ * file system on Android, VFAT, NTFS, etc., then git causes operations such as
+ * clone to fail with an error message.
+ *
+ * modified by Z.OOL. (mailto:zool@zool.jpn.org)
+ * ref.) https://github.com/termux/termux-packages/issues/227
+ */
+
+#define QUIET_CONFIG_LOCK_FAILURE 0
+#define WARN_CONFIG_LOCK_FAILURE 1
+#define ERROR_CONFIG_LOCK_FAILURE 2
+
+static void warn_config_lock_failure(void) {
+ static int _warned = 0;
+
+ if (!_warned) {
+ warning("Cannot lock .git/config bon this file system - For example, this file system is VFAT or NTFS, etc.");
+ _warned = 1;
+ }
+}
+
+static int error_level_config_lock_failure(void) {
+ static int _level = -1; const char *level;
+
+ if (_level < 0) {
+ if(git_config_get_string_const("core.errorLevelConfigLockFailure", &level) != 0) {
+ _level = WARN_CONFIG_LOCK_FAILURE;
+ return _level;
+ }
+
+ if (!strcmp(level, "error")) {
+ _level = ERROR_CONFIG_LOCK_FAILURE;
+ } else if (!strcmp(level, "warn")) {
+ _level = WARN_CONFIG_LOCK_FAILURE;
+ } else if (!strcmp(level, "quiet")) {
+ _level = QUIET_CONFIG_LOCK_FAILURE;
+ } else {
+ _level = WARN_CONFIG_LOCK_FAILURE;
+ }
+ }
+
+ return _level;
+}
+#endif
+
static int config_file_fgetc(struct config_source *conf)
{
return getc_unlocked(conf->u.file);
@@ -2817,9 +2864,23 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
in_fd = -1;
if (chmod(get_lock_file_path(&lock), st.st_mode & 07777) < 0) {
- error_errno(_("chmod on %s failed"), get_lock_file_path(&lock));
+#ifndef NO_USE_ERRLEVEL_CONFIG_LOCK_FAILURE
+ switch(error_level_config_lock_failure()) {
+ case ERROR_CONFIG_LOCK_FAILURE:
+ error_errno("chmod on %s failed", get_lock_file_path(&lock));
+ ret = CONFIG_NO_WRITE;
+ goto out_free;
+ case WARN_CONFIG_LOCK_FAILURE:
+ warn_config_lock_failure();
+ break;
+ case QUIET_CONFIG_LOCK_FAILURE:
+ break;
+ }
+#else
+ error_errno("chmod on %s failed", get_lock_file_path(&lock));
ret = CONFIG_NO_WRITE;
goto out_free;
+#endif
}
if (store.seen_nr == 0) {
@@ -3055,9 +3116,21 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
}
if (chmod(get_lock_file_path(&lock), st.st_mode & 07777) < 0) {
- ret = error_errno(_("chmod on %s failed"),
- get_lock_file_path(&lock));
+#ifndef NO_USE_ERRLEVEL_CONFIG_LOCK_FAILURE
+ switch(error_level_config_lock_failure()) {
+ case ERROR_CONFIG_LOCK_FAILURE:
+ ret = error_errno("chmod on %s failed", get_lock_file_path(&lock));
+ goto out;
+ case WARN_CONFIG_LOCK_FAILURE:
+ warn_config_lock_failure();
+ break;
+ case QUIET_CONFIG_LOCK_FAILURE:
+ break;
+ }
+#else
+ ret = error_errno("chmod on %s failed", get_lock_file_path(&lock));
goto out;
+#endif
}
while (fgets(buf, sizeof(buf), config_file)) {
diff --git a/git-gui/Makefile b/git-gui/Makefile
index f10caed..de285ae 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -57,7 +57,7 @@ INSTALL_X1 =
INSTALL_A0 = find # space is required here
INSTALL_A1 = | cpio -pud
INSTALL_L0 = rm -f # space is required here
-INSTALL_L1 = && ln # space is required here
+INSTALL_L1 = && ln -s # space is required here
INSTALL_L2 =
INSTALL_L3 =
@@ -87,7 +87,7 @@ ifndef V
INSTALL_L0 = dst=
INSTALL_L1 = && src=
INSTALL_L2 = && dst=
- INSTALL_L3 = && echo ' ' 'LINK ' `basename "$$dst"` '->' `basename "$$src"` && rm -f "$$dst" && ln "$$src" "$$dst"
+ INSTALL_L3 = && echo ' ' 'LINK ' `basename "$$dst"` '->' `basename "$$src"` && rm -f "$$dst" && ln -s "$$src" "$$dst"
CLEAN_DST = echo ' ' UNINSTALL
REMOVE_D0 = dir=
diff --git a/Makefile b/Makefile
index 537493822b..b8335ce4a8 100644
--- a/Makefile
+++ b/Makefile
@@ -2122,7 +2122,6 @@ version.sp version.s version.o: EXTRA_CPPFLAGS = \
$(BUILT_INS): git$X
$(QUIET_BUILT_IN)$(RM) $@ && \
- ln $< $@ 2>/dev/null || \
ln -s $< $@ 2>/dev/null || \
cp $< $@
@@ -2443,7 +2442,6 @@ git-remote-testsvn$X: remote-testsvn.o GIT-LDFLAGS $(GITLIBS) $(VCSSVN_LIB)
$(REMOTE_CURL_ALIASES): $(REMOTE_CURL_PRIMARY)
$(QUIET_LNCP)$(RM) $@ && \
- ln $< $@ 2>/dev/null || \
ln -s $< $@ 2>/dev/null || \
cp $< $@
@@ -2878,7 +2876,6 @@ endif
test -n "$(INSTALL_SYMLINKS)" && \
ln -s "$$destdir_from_execdir_SQ/$(bindir_relative_SQ)/$$p" "$$execdir/$$p" || \
{ test -z "$(NO_INSTALL_HARDLINKS)$(NO_CROSS_DIRECTORY_HARDLINKS)" && \
- ln "$$bindir/$$p" "$$execdir/$$p" 2>/dev/null || \
cp "$$bindir/$$p" "$$execdir/$$p" || exit; } \
done; \
} && \
@@ -2887,7 +2884,6 @@ endif
test -n "$(INSTALL_SYMLINKS)" && \
ln -s "git$X" "$$bindir/$$p" || \
{ test -z "$(NO_INSTALL_HARDLINKS)" && \
- ln "$$bindir/git$X" "$$bindir/$$p" 2>/dev/null || \
ln -s "git$X" "$$bindir/$$p" 2>/dev/null || \
cp "$$bindir/git$X" "$$bindir/$$p" || exit; } \
done && \
@@ -2896,7 +2892,6 @@ endif
test -n "$(INSTALL_SYMLINKS)" && \
ln -s "$$destdir_from_execdir_SQ/$(bindir_relative_SQ)/git$X" "$$execdir/$$p" || \
{ test -z "$(NO_INSTALL_HARDLINKS)" && \
- ln "$$execdir/git$X" "$$execdir/$$p" 2>/dev/null || \
ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \
cp "$$execdir/git$X" "$$execdir/$$p" || exit; } \
done && \
@@ -2906,7 +2901,6 @@ endif
test -n "$(INSTALL_SYMLINKS)" && \
ln -s "git-remote-http$X" "$$execdir/$$p" || \
{ test -z "$(NO_INSTALL_HARDLINKS)" && \
- ln "$$execdir/git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
ln -s "git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
cp "$$execdir/git-remote-http$X" "$$execdir/$$p" || exit; } \
done && \
diff --git a/config.c b/config.c
index 0f0cdd8c0f..bad2447a02 100644
--- a/config.c
+++ b/config.c
@@ -77,6 +77,53 @@ static int core_compression_seen;
static int pack_compression_seen;
static int zlib_compression_seen;
+#ifndef NO_USE_ERRLEVEL_CONFIG_LOCK_FAILURE
+/*
+ * If the git configuration file (.git/config) cannot be locked on a shared
+ * file system on Android, VFAT, NTFS, etc., then git causes operations such as
+ * clone to fail with an error message.
+ *
+ * modified by Z.OOL. (mailto:zool@zool.jpn.org)
+ * ref.) https://github.com/termux/termux-packages/issues/227
+ */
+
+#define QUIET_CONFIG_LOCK_FAILURE 0
+#define WARN_CONFIG_LOCK_FAILURE 1
+#define ERROR_CONFIG_LOCK_FAILURE 2
+
+static void warn_config_lock_failure(void) {
+ static int _warned = 0;
+
+ if (!_warned) {
+ warning("Cannot lock .git/config bon this file system - For example, this file system is VFAT or NTFS, etc.");
+ _warned = 1;
+ }
+}
+
+static int error_level_config_lock_failure(void) {
+ static int _level = -1; const char *level;
+
+ if (_level < 0) {
+ if(git_config_get_string_const("core.errorLevelConfigLockFailure", &level) != 0) {
+ _level = WARN_CONFIG_LOCK_FAILURE;
+ return _level;
+ }
+
+ if (!strcmp(level, "error")) {
+ _level = ERROR_CONFIG_LOCK_FAILURE;
+ } else if (!strcmp(level, "warn")) {
+ _level = WARN_CONFIG_LOCK_FAILURE;
+ } else if (!strcmp(level, "quiet")) {
+ _level = QUIET_CONFIG_LOCK_FAILURE;
+ } else {
+ _level = WARN_CONFIG_LOCK_FAILURE;
+ }
+ }
+
+ return _level;
+}
+#endif
+
static int config_file_fgetc(struct config_source *conf)
{
return getc_unlocked(conf->u.file);
@@ -2821,9 +2868,23 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
in_fd = -1;
if (chmod(get_lock_file_path(&lock), st.st_mode & 07777) < 0) {
- error_errno(_("chmod on %s failed"), get_lock_file_path(&lock));
+#ifndef NO_USE_ERRLEVEL_CONFIG_LOCK_FAILURE
+ switch(error_level_config_lock_failure()) {
+ case ERROR_CONFIG_LOCK_FAILURE:
+ error_errno("chmod on %s failed", get_lock_file_path(&lock));
+ ret = CONFIG_NO_WRITE;
+ goto out_free;
+ case WARN_CONFIG_LOCK_FAILURE:
+ warn_config_lock_failure();
+ break;
+ case QUIET_CONFIG_LOCK_FAILURE:
+ break;
+ }
+#else
+ error_errno("chmod on %s failed", get_lock_file_path(&lock));
ret = CONFIG_NO_WRITE;
goto out_free;
+#endif
}
if (store.seen_nr == 0) {
@@ -3059,9 +3120,21 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
}
if (chmod(get_lock_file_path(&lock), st.st_mode & 07777) < 0) {
- ret = error_errno(_("chmod on %s failed"),
- get_lock_file_path(&lock));
+#ifndef NO_USE_ERRLEVEL_CONFIG_LOCK_FAILURE
+ switch(error_level_config_lock_failure()) {
+ case ERROR_CONFIG_LOCK_FAILURE:
+ ret = error_errno("chmod on %s failed", get_lock_file_path(&lock));
+ goto out;
+ case WARN_CONFIG_LOCK_FAILURE:
+ warn_config_lock_failure();
+ break;
+ case QUIET_CONFIG_LOCK_FAILURE:
+ break;
+ }
+#else
+ ret = error_errno("chmod on %s failed", get_lock_file_path(&lock));
goto out;
+#endif
}
while (fgets(buf, sizeof(buf), config_file)) {
diff --git a/git-gui/Makefile b/git-gui/Makefile
index f10caedaa7..de285aeb4b 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -57,7 +57,7 @@ INSTALL_X1 =
INSTALL_A0 = find # space is required here
INSTALL_A1 = | cpio -pud
INSTALL_L0 = rm -f # space is required here
-INSTALL_L1 = && ln # space is required here
+INSTALL_L1 = && ln -s # space is required here
INSTALL_L2 =
INSTALL_L3 =
@@ -87,7 +87,7 @@ ifndef V
INSTALL_L0 = dst=
INSTALL_L1 = && src=
INSTALL_L2 = && dst=
- INSTALL_L3 = && echo ' ' 'LINK ' `basename "$$dst"` '->' `basename "$$src"` && rm -f "$$dst" && ln "$$src" "$$dst"
+ INSTALL_L3 = && echo ' ' 'LINK ' `basename "$$dst"` '->' `basename "$$src"` && rm -f "$$dst" && ln -s "$$src" "$$dst"
CLEAN_DST = echo ' ' UNINSTALL
REMOVE_D0 = dir=
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment