有没有一种简单的方法来交换暂存和非暂存的Git内容?

有没有一种简单的方法来交换暂存和非暂存的Git内容?,git,Git,有时候在做某件事的时候,我会发现一些需要先修复的东西。此时,我可能已经暂存了该文件的一部分和一些其他文件(新的和跟踪的),我想用当前暂存替换非暂存内容。有没有办法做到这一点 示例会话: $ cd "$(mktemp --directory)" $ git init Initialized empty Git repository in /tmp/tmp.7HssIqQ2qT/.git/ $ echo foo > foo $ echo bar > bar $ git add . $ g

有时候在做某件事的时候,我会发现一些需要先修复的东西。此时,我可能已经暂存了该文件的一部分和一些其他文件(新的和跟踪的),我想用当前暂存替换非暂存内容。有没有办法做到这一点

示例会话:

$ cd "$(mktemp --directory)"
$ git init
Initialized empty Git repository in /tmp/tmp.7HssIqQ2qT/.git/
$ echo foo > foo
$ echo bar > bar
$ git add .
$ git commit --message="Initial commit"
[master (root-commit) c6db082] Initial commit
 2 files changed, 2 insertions(+)
 create mode 100644 bar
 create mode 100644 foo
$ echo foo2 > foo
$ echo baz > baz
$ git add foo baz
$ echo foo3 >> foo
$ echo bar2 > bar
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   baz
    modified:   foo

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   bar
    modified:   foo
$cd“$(mktemp--目录)”
$git init
已在/tmp/tmp.7hssiqqqt/.Git中初始化空Git存储库/
$echo foo>foo
$echo条>条
$git add。
$git commit--message=“初始提交”
[主(根提交)c6db082]初始提交
2个文件已更改,2个插入(+)
创建模式100644条
创建模式100644 foo
$echo foo2>foo
$echo baz>baz
$git添加foo baz
$echo foo3>>foo
$echo bar2>条
$git状态
论分行行长
要提交的更改:
(使用“git重置磁头…”取消分级)
新档案:baz
修改:foo
未为提交而暂存的更改:
(使用“git add…”更新将提交的内容)
(使用“git签出--…”放弃工作目录中的更改)
修改:酒吧
修改:foo
基本上,我如何将上面的更改交换为提交,而将未暂存的更改交换为提交,记住对“foo”的更改只有一部分已暂存?到目前为止,我能想到的最简单的方法是创建两个隐藏并按相反顺序弹出它们,但效果不太好:

$ git stash --include-untracked --keep-index
Saved working directory and index state WIP on master: 3dba6aa Initial commit
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   baz
    modified:   foo
$ git stash --include-untracked
$ git status
On branch master
nothing to commit, working tree clean
$ git stash pop stash@{1}
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   baz

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   bar
    modified:   foo

Dropped stash@{1} (6fb8f81bdb2dc9fc1f218e7c25e74ad32c01fc0e)
$git存储--包括未跟踪--保留索引
主服务器上已保存的工作目录和索引状态WIP:3dba6aa初始提交
$git状态
论分行行长
要提交的更改:
(使用“git重置磁头…”取消分级)
新档案:baz
修改:foo
$git存储--包括未跟踪
$git状态
论分行行长
没什么要承诺的,正在清理树
$git stash pop stash@{1}
论分行行长
要提交的更改:
(使用“git重置磁头…”取消分级)
新档案:baz
未为提交而暂存的更改:
(使用“git add…”更新将提交的内容)
(使用“git签出--…”放弃工作目录中的更改)
修改:酒吧
修改:foo
丢弃的存储空间{1}(6fb8f81bdb2dc9fc1f218e7c25e74ad32c01fc0e)

不知怎的,baz是作为最古老的藏品的一部分而出现的,所以这个州已经一团糟了。

嗯。。。也许还有其他更优雅的方法,但你可以这样做:

# save content from index into a temp file
git show :0:path-to-file > file-from-index
# if content is in file-from-index, continue with the recipe
# save file from working tree into index
git add path-to-file
# move file as you saved from index into the right working tree path
mv file-from-index path-to-file

好了。

注意:在我开始回答下面的问题之前,我有两个注意事项:

  • 您最好使用
    git worktree add
    并在两个分支中工作,或者只是现在提交然后稍后重新排列。如果您现在提交,以后可以使用
    git-rebase-i
    交换提交的顺序。我认为,这可以让您更优雅地实现下一个要点中的补丁将要实现的功能。(但您必须记住重新设置基准。)

  • 下面的技巧使用完整的快照,您可能会根据差异来考虑,在这种情况下,两个
    git read tree
    s可能无法得到您想要的。试试看,看看这是不是你想要的。如果这不是你想要的,考虑通过<代码> Git DIF--缓存< /COD>两个补丁,然后<代码> Git DIF.< /代码>,保存这两个,进行硬重置,然后依次应用两个补丁,使用<代码> Git AdP;git提交它们之间的代码。请注意,这可能会导致合并冲突

无论如何,我不认为有什么特别优雅的东西,但是
git stash
——即使没有
——keep index
——也许能让你得到你想要的提交。(注意:我建议不要使用
——包括未跟踪的

请记住,提交是(或者更确切地说,包含)每个文件的完整快照,或者更具体地说,是提交时索引中的每个文件的完整快照。同时,索引中包含的是每个文件的完整副本。工作树上的内容由你决定;Git只会将文件从工作树复制到索引中(
Git add
),或从索引中复制到工作树中(
Git restore
,在2.23及更高版本中)。1

同时,一个简单的
gitcommit
可以从索引中的任何内容进行新的提交。如果这与
HEAD
中的内容相匹配,则需要添加一个标志2,但它就是这样做的。将其与git stash进行比较,git stash会进行两次或三次提交。第一个提交像往常一样从索引中进行,只是它不在任何分支上。第二次提交是将当前跟踪的工作树文件(索引中的文件)复制到索引中,以便第二次提交包含跟踪的工作树文件。第三次提交(如果存在)3包含不在第二次提交中的工作树文件(随后已被删除)。我们可以调用前两个提交
I
W
,并按照链接和阅读讨论部分进行操作

因此,运行
git stash
会创建两个提交,每个提交都保存您现在希望在工作树(即
I
commit)或索引(即
W
commit)中保存的文件。因此,我们现在可以使用new
git restore
命令更新工作树,然后使用
git read tree
填充索引,或者使用两个单独的
git read tree
命令(在任何版本的git中):

之后,我们可以使用git stash drop
git stash drop
(尽管我不在这里)

这里有一个稍微棘手的部分是,
baz
,它是新的,位于
W
commit中,因此出现在
提交阶段的更改
部分。因此:

分支主机上的

要提交的更改:
(使用“git还原--暂存…”取消暂存)
修改:酒吧
新档案:baz
修改:foo
未为提交而暂存的更改:
(使用“git add…”更新通信内容)
git stash                  # make commits I and W which are stash^2 and stash
git read-tree -mu stash^2  # copy I commit to index and work-tree
git read-tree stash        # copy W commit to index, leaving work-tree untouched
commit -> index                # e.g., git reset --mixed
          index -> work-tree   # e.g., git checkout-index / git restore
          index <- work-tree   # e.g., git add
git stash -k
git read-tree -um @; git cherry-pick -nm2 stash
git read-tree -um stash^2
git read-tree -um stash
git stash drop