Mar*_*osi 4647 git branching-and-merging git-branch
我想把我已经承诺掌握的最后几个提交移动到一个新的分支,然后在完成这些提交之前把主人带回去.不幸的是,我的Git-fu还不够强大,有什么帮助吗?
即我怎么能从这里走出来
master A - B - C - D - E
Run Code Online (Sandbox Code Playgroud)
这个?
newbranch C - D - E
/
master A - B
Run Code Online (Sandbox Code Playgroud)
syk*_*ora 5947
警告:此方法有效,因为您使用第一个命令创建新分支:--keep
.如果要将提交移动到现有分支,则需要在执行之前将更改合并到现有分支中git checkout
(请参阅下面的移动到现有分支).如果您不先合并更改,它们将会丢失.
除非涉及其他情况,否则可以通过分支和回滚轻松完成.
git checkout existingbranch
git merge master # Bring the commits here
git checkout master
git reset --keep HEAD~3 # Move master back by 3 commits.
git checkout existingbranch
Run Code Online (Sandbox Code Playgroud)
但要确保要返回多少次提交.或者,您可以代替git stash
提供您想要在主(/ current)分支上"恢复" 的提交(或者像origin/master这样的引用)的哈希,例如:
git branch newbranch # Create a new branch, containing all current commits
git reset --keep HEAD~3 # Move master back by 3 commits (Make sure you know how many commits you need to go back)
git checkout newbranch # Go to the new branch that still has the desired commits
# Warning: after this it's not safe to do a rebase in newbranch without extra care.
Run Code Online (Sandbox Code Playgroud)
*1您只会从主分支"丢失"提交,但不要担心,您将在newbranch中进行这些提交!
警告:对于Git 2.0及更高版本,如果您稍后--hard
在原始(git branch newbranch
)分支上使用新分支,则HEAD~3
在rebase期间可能需要一个显式选项以避免丢失结转提交.拥有origin/master
一套使这个可能性比较大.有关详细信息,请参阅John Mellor的答案.
如果要将提交移动到现有分支,它将如下所示:
git reset --keep a1b2c3d4
Run Code Online (Sandbox Code Playgroud)
Rya*_*ndy 975
对于那些想知道它为什么起作用的人(就像我一开始):
您想要返回到C,并将D和E移动到新分支.这是它最初的样子:
A-B-C-D-E (HEAD)
?
master
Run Code Online (Sandbox Code Playgroud)
之后git branch newBranch
:
newBranch
?
A-B-C-D-E (HEAD)
?
master
Run Code Online (Sandbox Code Playgroud)
之后git reset --hard HEAD~2
:
newBranch
?
A-B-C-D-E (HEAD)
?
master
Run Code Online (Sandbox Code Playgroud)
由于分支只是一个指针,因此master指向最后一次提交.当你创建newBranch时,你只需要创建一个指向最后一次提交的新指针.然后使用git reset
你将主指针移回两次提交.但是既然你没有移动newBranch,它仍然指向它最初的提交.
Iva*_*van 427
在这种情况下,sykora公开的方法是最佳选择.但有时并不是最容易的,也不是一般的方法.对于一般方法,使用git cherry-pick:
要实现OP想要的,它需要两个步骤:
newbranch
执行
git checkout master
git log
Run Code Online (Sandbox Code Playgroud)
注意你想要的哈希(比如3)提交newbranch
.在这里我将使用:
C commit:9aa1233
D commit:453ac3d
E commit:612ecb3
注意:您可以使用前七个字符或整个提交哈希
newbranch
git checkout newbranch
git cherry-pick 612ecb3
git cherry-pick 453ac3d
git cherry-pick 9aa1233
Run Code Online (Sandbox Code Playgroud)
git checkout newbranch
git cherry-pick 612ecb3~1..9aa1233
Run Code Online (Sandbox Code Playgroud)
git cherry-pick将这三个提交应用于newbranch.
ara*_*aer 306
另一种方法是使用2个命令.还可以保持当前工作树的完整性.
git checkout -b newbranch # switch to a new branch
git branch -f master HEAD~3 # make master point to some older commit
Run Code Online (Sandbox Code Playgroud)
旧版本 - 在我了解之前git branch -f
git checkout -b newbranch # switch to a new branch
git push . +HEAD~3:master # make master point to some older commit
Run Code Online (Sandbox Code Playgroud)
能够push
到.
是一个不错的把戏就知道了.
Joh*_*lor 295
不要这样做:
git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch
Run Code Online (Sandbox Code Playgroud)
当你下次运行git rebase
(或git pull --rebase
)时,这3个提交将被默默地丢弃newbranch
!(见下面的解释)
而是这样做:
git reset --keep HEAD~3
git checkout -t -b newbranch
git cherry-pick ..HEAD@{2}
Run Code Online (Sandbox Code Playgroud)
--keep
就像是--hard
,但更安全,因为失败而不是丢弃未提交的更改).newbranch
.newbranch
.由于它们不再被分支引用,它通过使用git的reflog来实现:HEAD@{2}
是HEAD
用于引用2个操作之前的提交,即在我们签出之前newbranch
和2.用于git reset
丢弃3个提交之前.警告:默认情况下启用reflog,但如果您手动禁用它(例如,通过使用"裸"git存储库),则运行后将无法恢复3次提交git reset --keep HEAD~3
.
不依赖于reflog的替代方案是:
# newbranch will omit the 3 most recent commits.
git checkout -b newbranch HEAD~3
git branch --set-upstream-to=oldbranch
# Cherry-picks the extra commits from oldbranch.
git cherry-pick ..oldbranch
# Discards the 3 most recent commits from oldbranch.
git branch --force oldbranch oldbranch~3
Run Code Online (Sandbox Code Playgroud)
(如果你愿意,你可以写@{-1}
- 以前签出的分支 - 而不是oldbranch
).
为什么git rebase
在第一个例子之后丢弃3个提交?这是因为git rebase
没有参数--fork-point
默认启用该选项,它使用本地reflog尝试对强制推送的上游分支进行强制.
假设你在包含提交M1,M2,M3的情况下分支origin/master,然后自己做三次提交:
M1--M2--M3 <-- origin/master
\
T1--T2--T3 <-- topic
Run Code Online (Sandbox Code Playgroud)
但后来有人通过强制推动origin/master删除M2来重写历史记录:
M1--M3' <-- origin/master
\
M2--M3--T1--T2--T3 <-- topic
Run Code Online (Sandbox Code Playgroud)
使用本地reflog,git rebase
可以看到您从origin/master分支的早期版本分叉,因此M2和M3提交实际上不是主题分支的一部分.因此,它合理地假设,由于M2已从上游分支中删除,因此在主题分支重新定位后,您不再需要在主题分支中使用它:
M1--M3' <-- origin/master
\
T1'--T2'--T3' <-- topic (rebased)
Run Code Online (Sandbox Code Playgroud)
这种行为是有道理的,并且在变基时通常是正确的做法.
所以以下命令失败的原因:
git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch
Run Code Online (Sandbox Code Playgroud)
是因为他们让reflog处于错误的状态.Git认为newbranch
已经在包含3次提交的修订版中分离了上游分支,然后reset --hard
重写上游的历史记录以删除提交,因此下次运行git rebase
它时会丢弃它们,就像从上游删除的任何其他提交一样.
但在这种特殊情况下,我们希望将这3个提交视为主题分支的一部分.为了实现这一点,我们需要在不包含3次提交的早期版本中分离上游.这就是我建议的解决方案,因此他们都将reflog保持在正确的状态.
有关详细信息,请参阅定义--fork-point
在git的底垫和混帐合并基础文档.
Sla*_*lam 109
如果:
master
,和然后以下更简单(从master
具有三个错误提交的分支开始):
git reset HEAD~3
git stash
git checkout newbranch
git stash pop
Run Code Online (Sandbox Code Playgroud)
master
,但保留所有工作文件master
工作树完全等于HEAD~3状态newbranch
您现在可以使用git add
,并git commit
像往常一样.所有新提交都将添加到newbranch
.
OP表示目标是"在做出这些提交之前将主人带回来"而不会丢失更改,这个解决方案就是这样做的.
我每周至少做一次,因为我不小心做了新的提交master
而不是develop
.通常我只有一次提交回滚,在这种情况下使用git reset HEAD^
第1行是一种简单的方法来回滚一次提交.
如果您将master的更改推送到上游,请不要这样做
其他人可能已经取消了这些变化.如果你只是重写你的本地主人,当它被推向上游时没有任何影响,但是将重写的历史推送给协作者可能会引起麻烦.
Suk*_*ima 30
这不会在技术意义上"移动"它们,但它具有相同的效果:
A--B--C (branch-foo)
\ ^-- I wanted them here!
\
D--E--F--G (branch-bar)
^--^--^-- Opps wrong branch!
While on branch-bar:
$ git reset --hard D # remember the SHAs for E, F, G (or E and G for a range)
A--B--C (branch-foo)
\
\
D-(E--F--G) detached
^-- (branch-bar)
Switch to branch-foo
$ git cherry-pick E..G
A--B--C--E'--F'--G' (branch-foo)
\ E--F--G detached (This can be ignored)
\ /
D--H--I (branch-bar)
Now you won't need to worry about the detached branch because it is basically
like they are in the trash can waiting for the day it gets garbage collected.
Eventually some time in the far future it will look like:
A--B--C--E'--F'--G'--L--M--N--... (branch-foo)
\
\
D--H--I--J--K--.... (branch-bar)
Run Code Online (Sandbox Code Playgroud)
teh*_*aus 24
要在不重写历史记录的情况下执行此操作(即,如果您已经推送了提交):
git checkout master
git revert <commitID(s)>
git checkout -b new-branch
git cherry-pick <commitID(s)>
Run Code Online (Sandbox Code Playgroud)
然后可以无力推动两个分支!
Sai*_*pta 17
1.将master
分支重命名为您的newbranch
(假设您在master
分支上):
git branch -m newbranch
Run Code Online (Sandbox Code Playgroud)
2.master
从您希望的提交创建分支:
git checkout -b master <seven_char_commit_id>
Run Code Online (Sandbox Code Playgroud)
例如 git checkout -b master a34bc22
Dar*_*low 13
只是这种情况:
Branch one: A B C D E F J L M
\ (Merge)
Branch two: G I K N
Run Code Online (Sandbox Code Playgroud)
我表演了:
git branch newbranch
git reset --hard HEAD~8
git checkout newbranch
Run Code Online (Sandbox Code Playgroud)
我期望提交我将成为HEAD,但现在提交L就是......
为了确保在历史上的正确位置,它更容易使用提交的哈希
git branch newbranch
git reset --hard #########
git checkout newbranch
Run Code Online (Sandbox Code Playgroud)
小智 11
总长DR
git checkout branch_to_remove_commits
git reset --hard ${hash_of_new_tip}
git checkout -b branch_to_store_commits
# Move commits (single hash, list of hashes or range ffaa..ffoo)
git cherry-pick ${commit_hash}
git push --set-upstream origin branch_to_store_commits
# Switch back to last branch
git checkout -
git push -f
Run Code Online (Sandbox Code Playgroud)
为我
git log --pretty=oneline -n ${NUMBER}
Run Code Online (Sandbox Code Playgroud)
最适合识别有问题的提交哈希。
如果您只需要将所有未推送的提交移动到新分支,那么您只需要,
从当前分支创建一个新分支:git branch new-branch-name
推送你的新分支:git push origin new-branch-name
将您的旧(当前)分支恢复到上次推送/稳定状态:git reset --hard origin/old-branch-name
有些人也有其他upstreams
而不是origin
,他们应该使用适当的upstream
只需我使用的 3 个简单步骤,您就可以做到这一点。
1)在您想要提交最近更新的地方创建新分支。
git branch <branch name>
2) 查找新分支上提交的最近提交 ID。
git log
3) 复制该提交 ID,请注意,最近的提交列表位于顶部。这样你就可以找到你的提交。您也可以通过消息找到此信息。
git cherry-pick d34bcef232f6c...
您还可以提供一些提交 ID 范围。
git cherry-pick d34bcef...86d2aec
现在你的工作完成了。如果你选择了正确的 id 和正确的分支,那么你就会成功。所以在做这件事之前要小心。否则可能会出现另一个问题。
现在您可以推送您的代码
git push
1) 创建一个新分支,将所有更改移动到 new_branch。
git checkout -b new_branch
Run Code Online (Sandbox Code Playgroud)
2)然后回到旧分支。
git checkout master
Run Code Online (Sandbox Code Playgroud)
3)进行git rebase
git rebase -i <short-hash-of-B-commit>
Run Code Online (Sandbox Code Playgroud)
4)然后打开的编辑器包含最后3次提交信息。
...
pick <C's hash> C
pick <D's hash> D
pick <E's hash> E
...
Run Code Online (Sandbox Code Playgroud)
5)在所有这 3 次提交中更改pick
为。drop
然后保存并关闭编辑器。
...
drop <C's hash> C
drop <D's hash> D
drop <E's hash> E
...
Run Code Online (Sandbox Code Playgroud)
6) 现在最后 3 个提交已从当前分支 ( master
) 中删除。现在用力推动分支,并+
在分支名称前加上符号。
git push origin +master
Run Code Online (Sandbox Code Playgroud)
我该如何去
A - B - C - D - E
|
master
Run Code Online (Sandbox Code Playgroud)
对此吗?
A - B - C - D - E
| |
master newbranch
Run Code Online (Sandbox Code Playgroud)
用两个命令
给予
A - B - C - D - E
|
newbranch
Run Code Online (Sandbox Code Playgroud)
和
给予
A - B - C - D - E
| |
master newbranch
Run Code Online (Sandbox Code Playgroud)
我很惊讶没有人推荐这种方式:
git checkout master
git checkout <commit hash from which you want to split>
git checkout -b new_branch
git rebase master
git checkout master
git reset --hard <commit hash you splitted>
Run Code Online (Sandbox Code Playgroud)
解释: