如何在git中执行"仅本地提交"?

nne*_*neo 45 git

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

目前,当我提交将提交重新排序回顶部时,我手动重新绑定,并且我推动使用HEAD^以避免推送本地更改.我也考虑过把这些变化放在藏匿处,但那不太方便,因为它排除了正常使用藏匿处.另一种方法是简单地将所有这些本地更改保留为未分级,并在git add -p每次我想要提交时使用.然而,随着大量琐碎的局部变化,这变得麻烦.

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

我的存储库最初看起来像

A---B---C---F master
Run Code Online (Sandbox Code Playgroud)

其中"F"是我的浮动提交.

我做了一个提交:

A---B---C---F---D master
Run Code Online (Sandbox Code Playgroud)

然后git rebase -i HEAD~2重新排序:

A---B---C---D---F master
Run Code Online (Sandbox Code Playgroud)

然后git push remote HEAD~1...推送除了本地F提交之外的所有内容.

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

kol*_*aTM 20

如何将这些更改放入您从主开发分支定期重新定位/合并的本地分支中?这样就没有任何上游承诺的危险.


Jon*_*mer 16

所以,听起来你想要两件事:

  • 一些提交应该保密(例如在本地分支上),并且当你拉动时从不推送或合并; 它们应该保留在"共享提交之后".

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

因此,您希望编写一个脚本(git-something将其命名并将其放在路径上,这是一个额外的git命令)来识别和处理这些提交.您需要一些触发器来让脚本识别本地提交.执行此操作的简单方法是在提交描述中添加一个神奇的单词 - 您将永远不会在真实/共享提交中使用 - 以供脚本识别.(如果这对你来说太过分散,你也可以在提交树中使用一个特殊的文件,比如.THIS_COMMIT_IS_LOCAL_ONLY;我在示例中没有这样做,因为它有点困难.)

您需要一个命令来从当前索引/ workdir进行本地提交; 这很容易,它只是调用git commit $@ -m "__LOCAL_COMMIT_ONLY__"(这是一个例子;关键是它做了什么来标记提交被创建为仅本地,然后遵循git提交).您还需要一个命令来暂时弹出所有本地提交,执行其他一些git命令(pull,push,fetch,merge等),然后重新应用本地提交.您还将使用此命令创建您打算共享的本地提交,以便它们始终显示在历史记录中仅限本地提交的"下方".

这是一个示例脚本,可以同时为您提供:

#!/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
Run Code Online (Sandbox Code Playgroud)

现在,假设您调用脚本git-local,使用git local new从索引创建一个新的仅本地提交(或git local new -a从workdir中的已修改文件创建),git local commit(名称不完美,遗憾地)创建一个新的"真正"提交,git local push推,git local pull拉等

这个的主要缺点是它要求你记住大多数命令现在都带有前缀local.如果你忘记这样做一次,你会有点h,但不会太糟糕 - 快速git rebase -i将让你轻松地将你的本地提交回到顶部然后你再次开始运行.最大的风险是您不小心使用git push而不是git local push上游发送所有私人更改,这将使每个人烦恼.为此,您可能希望实际编写一个小包装器脚本来调用而不是git本身(调用它~/bin/git并确保~/bin在您的路径上):

#!/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 "$@"
Run Code Online (Sandbox Code Playgroud)

您还可以pre-receive在服务器上创建一个自动拒绝__LOCAL_COMMIT_ONLY__其消息中包含的任何提交的挂钩.


Bey*_*mor 11

在以前的工作中,每个人都有自己的本地settings分支,我们在其上提交了我们的个人设置.这个分支是基于master; 任何主题分支都是分支的settings.当主题准备好集成时,我们将它们重新定位到master.这似乎是@koljaTM的建议.

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

rebase --onto master settings topic

A---B---C  master
        |\
        | F  settings
         \
          D  topic
Run Code Online (Sandbox Code Playgroud)

当新的变化打master,我们会重订settingsmaster,那么重订我们的工作就关闭任何主题settings.

不可否认,这不是一步一步"永远留下这个浮动"的解决方案,但它足够干净和简单.


Luk*_*uke 10

您可以使用可以从Git生成的补丁文件.

# git diff > local.patch
Run Code Online (Sandbox Code Playgroud)

如果要提交,请反向修补:

# git apply -R local.patch
Run Code Online (Sandbox Code Playgroud)

提交后,恢复补丁:

# git apply local.patch
Run Code Online (Sandbox Code Playgroud)

在创建补丁文件之前,您只需确保工作树上只有本地更改.创建补丁文件后,您可以将其添加到.gitignore您不提交的位置.

  • 这是完美的,这样的功能通常只需要少量提交或少量更改,只需应用/反转补丁...太棒了! (2认同)
  • 这是迄今为止我见过的最简单的解决方案。而且很干净! (2认同)