git reset --soft的实际用途?

AJJ*_*AJJ 117 git

我一直在用git工作一个多月.事实上我昨天才第一次使用复位,但软复位对我来说仍然没有多大意义.

据我所知,我可以使用软重置编辑提交而不改变索引或工作目录git commit --amend.

这两个命令是否真的相同(reset --softvs commit --amend)?有任何理由在实际中使用其中一个吗?更重要的是,reset --soft除了修改提交之外还有其他用途吗?

Von*_*onC 98

git reset所有关于移动HEAD,通常是分支参考.
问题:工作树和索引怎么样?
当使用--soft,移动HEAD,最常更新分支ref,而且只有HEAD.
这与以下不同commit --amend:

  • 它不会创建新的提交.
  • 它实际上可以将HEAD移动到任何提交(因为commit --amend只是移动HEAD,同时允许重做当前提交)

刚刚找到这个组合的例子:

  • 经典合并
  • 子树合并

all into one(章鱼,因为合并了两个以上的分支)提交合并.

Tomas"wereHamster"Carnecky在他的"Subtree Octopus merge"文章中解释道:

  • 如果要将一个项目合并到另一个项目的子目录中,并且随后使子项目保持最新,则可以使用子树合并策略.它是git子模块的替代品.
  • 章鱼合并策略可用于合并三个或更多分支.正常策略只能合并两个分支,如果你尝试合并更多,git会自动回退到章鱼策略.

问题是你只能选择一种策略.但是我希望将两者结合起来以获得一个干净的历史记录,其中整个存储库被原子地更新为新版本.

我有一个超级项目,让我们称它projectA,和一个子项目,projectB我合并到一个子目录projectA.

(这是子树合并部分)

我也在维护一些本地提交.
ProjectA定期更新,projectB每隔几天或几周都有一个新版本,通常取决于特定版本projectA.

当我决定更新这两个项目时,我不会简单地从中拉出来projectA,projectB 因为这将为整个项目的原子更新创建两个提交.
相反,我创建一个单一的合并提交它结合了projectA,projectB和我的本地提交.
这里棘手的部分是这是一个章鱼合并(三个头),projectB需要与子树策略合并.所以这就是我做的:

# Merge projectA with the default strategy:
git merge projectA/master

# Merge projectB with the subtree strategy:
git merge -s subtree projectB/master
Run Code Online (Sandbox Code Playgroud)

在这里,作者使用a reset --hard,然后read-tree恢复前两个合并对工作树和索引所做的事情,但这reset --soft可以帮助:
如何重做那两个合并,哪些有效,即我的工作树和索引是很好,但无需记录这两个提交?

# Move the HEAD, and just the HEAD, two commits back!
git reset --soft HEAD@{2}
Run Code Online (Sandbox Code Playgroud)

现在,我们可以恢复Tomas的解决方案:

# Pretend that we just did an octopus merge with three heads:
echo $(git rev-parse projectA/master) > .git/MERGE_HEAD
echo $(git rev-parse projectB/master) >> .git/MERGE_HEAD

# And finally do the commit:
git commit
Run Code Online (Sandbox Code Playgroud)

所以,每次:

  • 你对你最终得到的结果感到满意(在工作树和索引方面)
  • 你是不是满意,所有的带你到那里的提交:

git reset --soft 是答案.

  • 自我注意:使用`git reset --soft`压缩的简单示例:http://stackoverflow.com/questions/6869705/git-rebase-seems-to-have-worked-but-all-commits-are-still -showing合的日志-W (7认同)
  • 如果您提交错误的分支,它也很有用.所有更改都会返回到临时区域,并在您检查右侧分支时随身携带. (3认同)

Sha*_*tin 37

用例 - 组合一系列本地提交

"糟糕.这三个提交可能只是一个."

因此,撤消最后3次(或其他)提交(不影响索引和工作目录).然后将所有更改作为一个提交.

例如

> git add -A; git commit -m "Start here."
> git add -A; git commit -m "One"
> git add -A; git commit -m "Two"
> git add -A' git commit -m "Three"
> git log --oneline --graph -4 --decorate

> * da883dc (HEAD, master) Three
> * 92d3eb7 Two
> * c6e82d3 One
> * e1e8042 Start here.

> git reset --soft HEAD~3
> git log --oneline --graph -1 --decorate

> * e1e8042 Start here.
Run Code Online (Sandbox Code Playgroud)

现在,所有更改都会保留,并且可以作为一个更改提交.

简短回答你的问题

这两个命令是否真的相同(reset --softvs commit --amend)?

  • 没有.

有任何理由在实际中使用其中一个吗?

  • commit --amend 从最后一次提交添加/ rm文件或更改其消息.
  • reset --soft <commit> 将几个顺序提交组合成一个新的.

更重要的是,reset --soft除了修改提交之外还有其他用途吗?

  • 看其他答案:)

  • 请参阅"除了修改提交之外还有什么其他用于`reset --soft`的用法 - 否" (2认同)

Sim*_*mon 16

我用它来修改不仅仅是最后一次提交.

假设我在提交A中犯了一个错误然后提交了B.现在我只能修改B.所以我这样做git reset --soft HEAD^^,我纠正并重新提交A然后重新提交B.

当然,对于大型提交来说它不是很方便......但是你不应该做大量的提交;-)

  • `git commit --fixup HEAD ^^``git rebase --autosquash HEAD~X`也很好用. (3认同)
  • `git rebase --interactive HEAD ^^`你选择**编辑**提交A和B.这样可以保存A和B的提交消息,如果需要你还可以修改它们. (3认同)
  • 重置为A后,如何重新提交B? (2认同)

del*_*rux 13

另一个潜在用途是作为存储的替代方法(有些人不喜欢,例如https://codingkilledthecat.wordpress.com/2012/04/27/git-stash-pop-considered-harmful/).

例如,如果我正在分支机构并且需要在master上紧急修复某些东西,我可以这样做:

git commit -am "In progress."
Run Code Online (Sandbox Code Playgroud)

然后结帐大师并做修复.当我完成后,我会回到我的分支机构做

git reset --soft HEAD~1
Run Code Online (Sandbox Code Playgroud)

继续在我离开的地方工作.

  • 更新(现在,我对git有了更好的了解):除非您真的关心立即进行更改,否则在这里实际上不需要`--soft`。我现在在执行此操作时只使用`git reset HEAD〜`。如果当我需要切换分支时要进行一些更改,并希望保持这种状态,那么我先执行git commit -m“ staged changes”,然后执行git commit -am“ unstaged changes”,然后再执行` git reset HEAD〜然后是git reset --soft HEAD〜可以完全恢复工作状态。虽然,老实说,我对`git-worktree`的了解现在减少了这两件事:) (2认同)

Joh*_*lph 6

您可以使用git reset --soft更改您希望拥有的版本作为索引和工作树中所做更改的父级.有用的情况很少见.有时您可能会认为工作树中的更改应属于不同的分支.或者你可以使用它作为一种简单的方法将几个提交折叠成一个(类似于壁球/折叠).

请参阅VonC的这个答案以获得一个实际的例子: 在Git中压缩前两个提交?


lla*_*lin 6

一种可能的用法是当您想要在另一台机器上继续工作时.它会像这样工作:

  1. 签出一个类似藏匿名称的新分支,

    git checkout -b <branchname>_stash
    
    Run Code Online (Sandbox Code Playgroud)
  2. 推开你的藏匿分支,

    git push -u origin <branchname>_stash
    
    Run Code Online (Sandbox Code Playgroud)
  3. 切换到您的其他机器.

  4. 拉下你的藏匿处和现有的树枝,

    git checkout <branchname>_stash; git checkout <branchname>
    
    Run Code Online (Sandbox Code Playgroud)
  5. 您现在应该在现有分支上.合并来自隐藏分支的更改,

    git merge <branchname>_stash
    
    Run Code Online (Sandbox Code Playgroud)
  6. 在合并之前将现有分支软重置为1,

    git reset --soft HEAD^
    
    Run Code Online (Sandbox Code Playgroud)
  7. 删除你的藏匿分支,

    git branch -d <branchname>_stash
    
    Run Code Online (Sandbox Code Playgroud)
  8. 同时从原点删除您的隐藏分支,

    git push origin :<branchname>_stash
    
    Run Code Online (Sandbox Code Playgroud)
  9. 继续处理您的更改,就好像您正常隐藏它们一样.

我想,在未来,GitHub和co.应该以更少的步骤提供这种"远程存储"功能.

  • 我想指出第一台机器上的第一个存储和弹出是完全没必要的,您可以直接从脏工作副本创建一个新分支,提交,然后将更改推送到远程. (2认同)

j2e*_*nue 6

一个实际用途是如果你已经提交到你的本地仓库(即.git commit -m)然后你可以通过执行git reset来反转最后一次提交--soft HEAD~1

另外据您所知,如果您已经进行了更改(例如使用git add.),那么您可以通过执行git reset来反转分段 - 混合HEAD或者我通常也只是使用git reset

最后,git reset --hard擦除所有内容,包括你的本地更改.〜后头告诉你从顶部有多少提交.


Haz*_*zok 5

使用' git reset --soft <sha1>'的一个很好的理由是进入HEAD一个简单的回购.

如果您尝试使用--mixed--hard选项,则会因为您尝试修改和处理不存在的树和/或索引而收到错误.

注意:您需要直接从裸仓库执行此操作.

再次注意:您需要确保要在裸仓库中重置的分支是活动分支.如果没有,请按照VonC的答案,了解如何在直接访问存储库时更新裸存储库中的活动分支.