将git commits应用到未添加的工作树?

ttp71kqs  于 2023-05-21  发布在  Git
关注(0)|答案(6)|浏览(252)

假设我有一个包含8次提交和一个分支(master)的线性git历史:
我想把master移到4(我可以用git branch -f master 4来做):
现在工作树处于状态4。
现在我想将来自4 -> 8的更改作为补丁应用到我的工作树。
也就是说,在不影响.git文件夹状态的情况下,我想将4->8 unstaged的更改应用到我的工作树。在此之后,工作树应该处于状态8,但提交状态和主分支应该处于状态4。
换个说法就是:假设在将master移到4之后,我手动地对我的工作树进行了从4->8的更改,而没有将它们添加到索引中。结果应该是一样的。
最简单的方法是什么?

c9x0cxw0

c9x0cxw01#

我知道我迟到了,但作为其他人的参考,我认为最简单的方法是:
git cherry-pick --no-commit 4..8

xe55xuns

xe55xuns2#

git format-patch 4..8 | xargs git apply

[edit:下面的注解中的下一个跳过制作单个补丁文件]

git diff 4..8 | git apply
pgvzfuti

pgvzfuti3#

在您的情况下,如果您实际上并不关心“未登台”的部分,那么最简单的做法可能是

git checkout 8 -- .

这将更新你的树和索引来匹配commit 8,而不会改变你的commit历史。然后,您可以git reset放弃索引更改。
如果你真的不想让索引文件受到干扰,那么它会稍微复杂一些,因为git总是从索引更新工作树。你可以这样做

GIT_INDEX_FILE=/tmp/foo git checkout 8 -- .

这将使用路径/tmp/foo作为此命令的临时索引文件。然后,您可能希望删除此文件。
在一个更复杂的情况下,如果你想重新应用补丁,而这些补丁实际上并不能把你带回到commit 8的精确状态,你可以使用git cherry-pick --no-commit commit1 commit2 ...来按顺序应用提交。当然,这仍然会修改索引。

j2cgzkjk

j2cgzkjk4#

使OP的状态发生:

cyclone% mkdir myrepo
cyclone% cd myrepo
cyclone% git init
Initialized empty Git repository in /tmp/myrepo/.git/
cyclone% echo 'Hello, world!' >hello
cyclone% git add hello
cyclone% git commit -m 'Initial import'
[master (root-commit) 6ec97b1] Initial import
 1 file changed, 1 insertion(+)
 create mode 100644 hello
cyclone% echo 'How are you?' >>hello
cyclone% git add hello
cyclone% git commit -m "Added 'How are you?'"
[master 8786161] Added 'How are you?'
 1 file changed, 1 insertion(+)
# Now, if I reset back, the commit object
# seems to be removed (possibly due to my current
# version of Git vs. OP's older version?). To prevent
# this, I'll "name" the commit OP considers '8'.
# Thus, OP would put the commit ID corresponding
# to their '8' wherever I put 'tip'.
cyclone% git branch tip
# In all my years, I've never heard of
# 'git branch --force' -- then again, I'm not
# Linus Torvalds, so I guess I know only like
# half of Git, as do all of you (unless you ARE
# Linus Torvalds). Nonetheless, if I try the next,
# commented-out line, I get:
#     fatal: Cannot force update the current branch.
#git branch -f master 'HEAD^'
# A (too?) quick Google doesn't really help on the
# matter, so... In the undying words of...
# well, somebody-or-other in the whole long history
# of ever: Lemme fix that for ya...
cyclone% git update-ref HEAD 'HEAD^'
# Now this is the crucial point: If this is going
# to be easy, you need a recent enough version of
# Git to support 'git restore', because that DOES
# make things easy (see below).
cyclone% git restore --staged .
# Now, this is actually the state OP wants, but
# since they are at a different state, I guess we'll
# wantonly destroy it...
cyclone% git checkout .
Updated 1 path from the index

这样,我们就处于OP的状态:

# We are on master, with no changes (staged nor unstaged)
# and master is the "old" commit:
cyclone% git status
On branch master
nothing to commit, working tree clean
# The working tree reflects the "old" commit:
cyclone% cat hello
Hello, world!
# Commit '8' (i.e. 'tip') reflects the "new"
# commit:
cyclone% git show tip:hello
Hello, world!
How are you?

所以,现在有一个简单的命令,可以将OP的当前状态带到OP的期望状态:

cyclone% git restore --source=tip .

现在我们正处于我们想要的位置:

# The changes between '4' and '8' are present, but
# not staged nor committed:
cyclone% git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   hello

no changes added to commit (use "git add" and/or "git commit -a")
# The current branch (master, as Git tells us above) is on
# what OP considers '4':
cyclone% git log
commit f4661e0c12a20acb6dd0bc4afe8c9b2301667608 (HEAD -> master)
Author: Simon "UncleSniper" Bausch <(REDACTED)>
Date:   (no matter)

    Initial import
# The working tree includes the changes between '4'
# and '8':
cyclone% cat hello
Hello, world!
How are you?
# The changes between '4' and '8' are "present" (see
# above), but neither staged nor committed:
cyclone% git diff
diff --git a/hello b/hello
index af5626b..b076fc1 100644
--- a/hello
+++ b/hello
@@ -1 +1,2 @@
 Hello, world!
+How are you?
# In fact, nothing is staged at all:
cyclone% git diff --cached
cyclone%

所以,在OP的当前状态和OP的期望状态之间只有一个命令(git restore --source=tip .)--假设Git的版本足够新。

1mrurvl1

1mrurvl15#

git checkout master@{1} -- .

就是你所需要的。它读作“checkout the files that the commit that master was pointed to one time ago”。查看git reflog以了解其工作原理。
此外,您不应该像以前那样强制重新创建分支。这将允许git跟踪master曾经指向的所有位置。使用方式

git stash -u

如果你在工作目录中有一些工作。然后

git reset --hard master^^^^

git reset --hard master~4
qni6mghb

qni6mghb6#

git cherry-pick master~4 master~5 master~6 master~7 master~8

你的工作树必须是干净的

git help cherry-pick

相关问题