git reset --soft的实际用途?

时间:2011-03-05 11:31:44

标签: git

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

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

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

10 个答案:

答案 0 :(得分:96)

git reset完全是关于移动HEADand generally the branch ref 问题:工作树和索引怎么样?
--soft一起使用时,会移动HEAD,通常会更新分支参考,只会更新HEAD 。 这与commit --amend不同:

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

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

  • 经典合并
  • 子树合并

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

Tomas "wereHamster" Carnecky在他的"Subtree Octopus merge" article

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

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

     

我有一个超级项目,我们称之为projectA,以及一个子项目projectB,我将其合并到projectA的子目录中。

(这是子树合并部分)

  

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

     

当我决定更新这两个项目时,我不会简单地从projectAprojectB 中提取,因为这将为整个项目的原子更新创建两个提交< / strong>即可。
  相反,我创建了一个合并提交,其中包含projectAprojectB和我的本地提交。   这里棘手的部分是这是一个章鱼合并(三个头),projectB需要与子树策略合并。所以这就是我的工作:

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

# Merge projectB with the subtree strategy:
git merge -s subtree projectB/master

在这里,作者使用reset --hard,然后read-tree来恢复前两个合并对工作树和索引所做的操作,但这就是 reset --soft < / strong>可以提供帮助:
如何重做那两个合并,哪些有效,即我的工作树和索引都没问题,但无需记录这两个提交?

# Move the HEAD, and just the HEAD, two commits back!
git reset --soft HEAD@{2}

现在,我们可以恢复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

所以,每次:

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

git reset --soft就是答案。

答案 1 :(得分:32)

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

&#34;糟糕。这三个提交可能只是一个。&#34;

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

E.g。

> 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.

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

您的问题的简短答案

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

  • 否。

有任何理由在实践中使用其中一种吗?

  • commit --amend从最后一次提交中添加/ rm文件或更改其消息。
  • reset --soft <commit>将多个顺序提交合并为一个新提交。

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

  • 见其他答案:)

答案 2 :(得分:16)

我用它来修改 last 提交。

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

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

答案 3 :(得分:9)

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

例如,如果我在分支机构工作并需要在主人身上紧急修理某些事情,我可以这样做:

git commit -am "In progress."

然后结帐主人并进行修复。当我完成后,我会回到我的分支机构并做

git reset --soft HEAD~1

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

答案 4 :(得分:6)

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

VonC的这个答案是一个实际的例子: Squash the first two commits in Git?

答案 5 :(得分:6)

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

  1. 以类似藏匿名称的方式签出新分支

    git checkout -b <branchname>_stash
    
  2. 推送你的藏匿分支,

    git push -u origin <branchname>_stash
    
  3. 切换到您的其他计算机。

  4. 拉下你的藏匿处和现有的分支,

    git checkout <branchname>_stash; git checkout <branchname>
    
  5. 您现在应该在现有分支上。合并来自隐藏分支的更改

    git merge <branchname>_stash
    
  6. 在合并之前将现有分支软复位为1,

    git reset --soft HEAD^
    
  7. 删除您的藏匿分支

    git branch -d <branchname>_stash
    
  8. 同时从原点删除您的隐藏分支

    git push origin :<branchname>_stash
    
  9. 继续使用您的更改,就像您正常隐藏它们一样。

  10. 我认为,在未来,GitHub和co。应该用更少的步骤提供这种“远程藏匿”功能。

答案 6 :(得分:5)

使用“git reset --soft <sha1>”的一个很好的理由是将HEAD移到一个简单的仓库中。

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

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

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

答案 7 :(得分:1)

SourceTree是一个git GUI,它有一个非常方便的界面,只需要暂存你想要的位。它没有任何类似的东西可以修改正确的版本。

因此git reset --soft HEAD~1在此方案中比commit --amend更有用。我可以撤消提交,将所有更改恢复到暂存区域,然后使用SourceTree继续调整暂存位。

实际上,在我看来,commit --amend是两者中更冗余的命令,但是git是git,并且不会回避那些略有不同的命令。

答案 8 :(得分:0)

虽然我真的很喜欢此线程中的答案,但我使用git reset --soft进行了稍有不同,但非常实用的情况。

我使用IDE进行开发,该IDE具有良好的差异工具,可显示上次提交后的更改(暂存和暂存)。现在,我的大部分任务都涉及多个提交。例如,假设我进行了5次提交以完成特定任务。在从1-5进行的每次增量提交期间,我都使用IDE中的diff工具查看从上一次提交所做的更改。我发现这是一种非常有用的方法,可以在提交之前查看我的更改。

但是,在我的任务结束时,当我想一起查看所有更改(在第一次提交之前)时,在发出请求之前进行自我代码审查,我只会看到上一次提交的更改(在提交4之后),并且不会从当前任务的所有提交中更改。

因此,我使用git reset --soft HEAD~4返回4次提交。这使我可以一起查看所有更改。当我对自己的更改充满信心后,便可以进行git reset HEAD@{1}并将其自信地推送到远程。

答案 9 :(得分:0)

另一个用例是,当您要在请求请求中用您的分支替换另一个分支时,例如,假设您在开发中拥有具有功能A,B,C的软件。

您正在开发下一个版本,并且您:

  • 已删除功能B

  • 添加了功能D

在此过程中,为功能B开发刚刚添加的修补程序。

您可以将开发合并到下一个,但是有时可能会很混乱,但是您也可以使用git reset --soft origin/develop并使用所做的更改创建提交,分支可以合并而不会发生冲突并保留您的更改。

事实证明git reset --soft是一个方便的命令。我个人经常使用它来压缩未完成“ WIP”之类的“完成工作”的提交,因此当我打开请求请求时,我的所有提交都是可以理解的。