Git 如何做一个;“仅本地提交”;用吉特?

Git 如何做一个;“仅本地提交”;用吉特?,git,Git,我正在使用git,我希望能够创建一个不与远程存储库同步的提交。这样的提交必须“浮动”在本地存储库中的所有其他提交之上,以避免影响历史记录。我可以使用这种提交来存储特定于本地的更改(配置更改、调试标志、本地解决方法等) 目前,我在提交时手动重新设置基址以将提交重新排序回顶部,并使用HEAD^推送以避免推送本地更改。我也考虑过把这些变化放在储藏室里,但这不太方便,因为它妨碍了储藏室的正常使用。另一种选择是,只需将所有这些本地更改保留为未标记状态,并在每次提交时使用git add-p。然而,由于有大量

我正在使用git,我希望能够创建一个不与远程存储库同步的提交。这样的提交必须“浮动”在本地存储库中的所有其他提交之上,以避免影响历史记录。我可以使用这种提交来存储特定于本地的更改(配置更改、调试标志、本地解决方法等)

目前,我在提交时手动重新设置基址以将提交重新排序回顶部,并使用
HEAD^
推送以避免推送本地更改。我也考虑过把这些变化放在储藏室里,但这不太方便,因为它妨碍了储藏室的正常使用。另一种选择是,只需将所有这些本地更改保留为未标记状态,并在每次提交时使用
git add-p
。然而,由于有大量琐碎的局部更改,这就成了一件麻烦事

以下是我当前工作流程的一个示例:

我的存储库最初看起来像

A---B---C---F master
其中“F”是我的浮动提交

我承诺:

A---B---C---F---D master
然后
git rebase-i HEAD~2
重新排序:

A---B---C---D---F master
然后,
git push remote HEAD~1…
推送除本地
F
commit之外的所有内容


更改F包含对现有版本化文件的更改,并且可能包含任意数量的更改。(如果我可以使多个提交“浮动”,那就更好了,因为我可以分离本地更改)。

您可以忽略git中的某些文件,这样它们就不会被推送到远程存储库。我这样做的方式是将这些文件保存在本地,而不是通过忽略它们而将它们推送到存储库

下面是gitignore的一些解释


如何将这些更改放到本地分支中,并定期从主开发分支重新设置/合并这些分支?这样就不会有任何向上游提交的危险。

在以前的工作中,每个人都有自己的本地
设置
分支,我们在其上提交了各自的设置。该分支基于
master
;任何主题分支都是从
设置中分支出来的。当主题准备好进行集成时,我们将它们重新放在
master
上。这似乎是@koljaTM的建议

A---B---C  master
         \
          F  settings
           \
            D  topic

rebase --onto master settings topic

A---B---C  master
        |\
        | F  settings
         \
          D  topic
当新的更改到达
master
时,我们将重新设置
master
设置的基础,然后重新设置我们在
设置的基础上正在处理的任何主题的基础


诚然,这不是一个“永远保持浮动”的一步解决方案,但它非常干净和简单。

我经常遇到这个问题,通常是从共享代码库中分离IDE设置等。这是一个非常常见的用例,您可能认为它现在已经解决了,但还没有解决。我不相信
git
能像你想的那样处理这个问题

问题归根结底是,您希望两个签出共享一个目录。为了让它工作,需要有一些数据结构,用户可以操作,标记哪些文件属于哪些签出。这也不是一对一的关系;在多个签出中包含一些文件是完全合理的。在所有情况下,您都需要以某种方式命名不同的签出以支持消除歧义。对于基本的健全性,您需要一个目录列表器,该列表器使用文件的签出关联对文件进行注释

作为一个特殊的例子,请考虑<代码> .GiGiGNOR./COD>。这是一个应用于“所有”签出的单个文件,隐式地表示“唯一签出”。为了让

.gitignore
正常工作,每次签出都需要一个,这是一种区分每次签出中不同文件的方法。然而,
git
中却没有这种基础设施的迹象

我解决这些问题的“标准”方法是安排事情,这样每个目录只需要一次签出。我创建了一个名为“custom”(或类似)的目录。该目录进入父目录中的
.gitignore
。在自定义目录中,我从不同的存储库和/或不同的位置进行了签出。这意味着两次承诺捕获所有更改;这在实践中很少是个问题


如果这会激发任何人攻击
git
,请添加“命名签出”选项,并将现有行为保留为匿名签出。您可以有[0..1]个匿名签出和[0..*)个命名签出。从这个基础上,您可能需要的其他大部分内容都非常自然。

您可以使用一个补丁文件,它可以从Git生成

# git diff > local.patch
当您要提交时,请反转修补程序:

# git apply -R local.patch
提交后,恢复修补程序:

# git apply local.patch

在创建修补程序文件之前,您只需确保工作树上只有您的本地更改。创建修补程序文件后,您可以将其添加到
.gitignore
,这样您就不会提交该文件。

如果您试图阻止的是实际提交,那么您的做法是正确的-使用

git-rebase-i

并将所有“个人提交”重新排序为最新提交,然后

git推送:


这将推动所有提交,包括您提供的SHA,但不是随后的“个人提交”。

因此,听起来您需要两件事:

  • 某些提交应保持私有(例如,在本地分支上),并且在拉取时从不推送或合并;它们应保持在共享提交之后

  • 这对您来说应该是透明的;您希望在master上工作,并自动维护本地分支。您只需决定哪些提交应该是本地的,而与远程存储库交互的命令将忽略这些提交

因此,您需要编写一个脚本(将其命名为git something
,并将其放在您的路径上,因此这是一个额外的git命令)来识别和处理这些提交。您需要一些触发器,让脚本能够识别本地提交
#!/bin/sh
if [[ $1 eq 'new' ]]; then
  shift
  exec git commit $@ -m "__LOCAL_COMMIT_ONLY__"
elif [[ $1 eq

OLD_HEAD=$(git rev-parse HEAD)
OLD_REAL_HEAD="$(git rev-list HEAD --grep=__LOCAL_COMMIT_ONLY__ | tail -n1)^"
git reset --soft $OLD_REAL_HEAD
git $@
git rebase --onto HEAD $OLD_REAL_HEAD $OLD_HEAD
#!/bin/sh
if [[ $1 = 'push' ]]; then
  if /usr/bin/git rev-list HEAD --grep=__LOCAL_COMMIT_ONLY__ | grep -q .; then
    echo "Can't push with local changes still active!"
    echo "Try using `git local push' instead."
    exit 1
  fi
fi
exec /usr/bin/git "$@"
[alias]
    local-export = "![ ${#} -eq 1 ] && CURRENT_BRANCH=$(git branch --show-current) && git checkout -b \"local/${1}\" && git commit --allow-empty -m ${1} && git checkout \"${CURRENT_BRANCH}\" || echo 'You must provide <local_branch_name>' #"
    local-import = "![ ${#} -eq 1 ] && CURRENT_BRANCH=$(git branch --show-current) && git merge \"local/${1}\" --no-ff --commit --no-edit && git reset HEAD^ || echo 'You must provide <local_branch_name>' #"
    local-delete = "![ ${#} -eq 1 ] && git branch -D \"local/${1}\" || echo 'You must provide <local_branch_name>' #"