git使用现有提交中的文件子集创建新提交

时间:2019-10-26 06:52:27

标签: git

有时候我需要将一个将多个文件接触的提交分解为单独的提交。

例如,假设我有一个涉及文件foobar的提交,并且我想分成两个提交,其中一个仅涉及foo,而其中一个仅涉及bar。假设我要拆分的提交是提示提交。

例如,假设这是我的存储库的历史记录

commit a78143999ebc8fb1d696832ed5ef2654a3325bb4
Author: Gregory Nisbet <>
Date:   Fri Oct 25 23:12:55 2019 -0700

    add both foo and bar

commit 760208789956815d471ccd1ce9b642b32299cbb3
Author: Gregory Nisbet <>
Date:   Fri Oct 25 23:12:25 2019 -0700

    empty foo and bar

我想将其更改为更多类似的内容。我在上面添加新提交的地方,仅涉及foo。在此特定示例中,第二个提交仅触摸bar。理想情况下,我希望能够通过使用foo和bar定位原始提交并提供放置新提交的路径来执行这种拆分。

commit 938b52c57511f1150ca0f1958458ece069205631
Author: Gregory Nisbet <>
Date:   Fri Oct 25 23:18:14 2019 -0700

    add foo only

commit d9c09b249f105ffd65f35392b26ac6a08f7effc2
Author: Gregory Nisbet <>
Date:   Fri Oct 25 23:12:55 2019 -0700

    add bar only

commit 760208789956815d471ccd1ce9b642b32299cbb3
Author: Gregory Nisbet <>
Date:   Fri Oct 25 23:12:25 2019 -0700

    empty foo and bar

我试图编写一个脚本,通过产生两个还原并将第一个还原修改为原始提交来执行这种拆分行为。

该脚本很丑陋,但在我尝试过的少数情况下确实可以运行,并且具有正确的API。

我感觉到必须有一种更直接的方法来实现我要尝试的工作。

#!/bin/bash


while getopts "m:" opt; do
    case "$opt" in
        m)
            message="$OPTARG" ;;
    esac
done

shift "$((OPTIND-1))"


if test -z "$message"; then
    1>&2 printf '%s\n' 'message cannot be empty'
    exit 20
fi

branch="$(python -c 'import uuid; print(str(uuid.uuid4()))')"

if 1>/dev/null 2>/dev/null git diff --exit-code; then
    : "do nothing"
else
    1>&2 printf '%s\n' 'working directory not clear'
    exit 30
fi
hash="$(git rev-parse --verify HEAD)"
# revert initial commit, write revert to index
git revert --no-commit -- "$hash" || exit 10
# remove paths specified on command line from index
git reset HEAD "$@" || { git revert --abort; exit 20; }
git checkout -- "$@" || { git revert --abort; exit 30; }
# commit partial revert
git commit --allow-empty-message --no-edit || exit 40
# revert the just-committed partial revert, keep
# the new double revert in the index
git revert --no-commit HEAD || exit 50
# checkout an unused branch
git checkout -b "$branch" || exit 60
# commit double revert
git commit --allow-empty-message --no-edit || exit 70
# go back to previous branch
git checkout - || exit 80
# uncommit the latest change (the first revert)
git reset --soft HEAD^ || exit 90
# amend first revert onto previous commit
git commit --amend --no-edit || exit 10
# go to scratch branch
git checkout "$branch" || exit 20
# revert latest change in scratch branch, keep it in the index
git reset --soft HEAD^ || exit 30
# go to previous branch
git checkout - || exit 40
# use our commit message to create a new commit with that message
git commit --no-edit --message="$message" || exit 50
# delete temporary branch
git branch -D "$branch" || exit 60

使用上述脚本,我可以仅使用gitsplit -m 'second commit' foo定位提示提交中路径的一部分。

$ git init                                                                                                                                                                                                                                                  
Initialized empty Git repository in /tmp/gitdir/.git/                                                                                                                                                                                                                                        

$ echo foo > foo                                                                                                                                                                                                                                            

$ echo bar > bar                                                                                                                                                                                                                                            

$ git add foo bar                                                                                                                                                                                                                                           

$ git commit -m 'initial commit'                                                                                                                                                                                                                            
[master (root-commit) 4472c3c] initial commit                                                                                                                                                                                                                                                
 2 files changed, 2 insertions(+)                                                                                                                                                                                                                                                            
 create mode 100644 bar                                                                                                                                                                                                                                                                      
 create mode 100644 foo                                                                                                                                                                                                                                                                      

$ gitsplit -m 'second commit' foo                                                                                                                                                                                                                           
Unstaged changes after reset:                                                                                                                                                                                                                                                                
D       foo                                                                                                                                                                                                                                                                                  
[master 9a5d357] Revert "initial commit"                                                                                                                                                                                                                                                     
 1 file changed, 1 deletion(-)                                                                                                                                                                                                                                                               
 delete mode 100644 bar                                                                                                                                                                                                                                                                      
A       bar                                                                                                                                                                                                                                                                                  
Switched to a new branch 'b70d1c24-aca5-4676-a287-d35dbe14f790'                                                                                                                                                                                                                              
[b70d1c24-aca5-4676-a287-d35dbe14f790 abb559a]                                                                                                                                                                                                                                               
 1 file changed, 1 insertion(+)                                                                                                                                                                                                                                                              
 create mode 100644 bar                                                                                                                                                                                                                                                                      
Switched to branch 'master'                                                                                                                                                                                                                                                                  
[master 5d95965] initial commit                                                                                                                                                                                                                                                              
 Date: Fri Oct 25 23:36:26 2019 -0700                                                                                                                                                                                                                                                        
 1 file changed, 1 insertion(+)                                                                                                                                                                                                                                                              
 create mode 100644 foo                                                                                                                                                                                                                                                                      
Switched to branch 'b70d1c24-aca5-4676-a287-d35dbe14f790'                                                                                                                                                                                                                                    
A       bar                                                                                                                                                                                                                                                                                  
Switched to branch 'master'                                                                                                                                                                                                                                                                  
[master 2f64de7] second commit                                                                                                                                                                                                                                                               
 1 file changed, 1 insertion(+)                                                                                                                                                                                                                                                              
 create mode 100644 bar                                                                                                                                                                                                                                                                      
Deleted branch b70d1c24-aca5-4676-a287-d35dbe14f790 (was 9a5d357).                                                                                                                                                                                                                           


$ git --no-pager show --format=short HEAD                                                                                                                                                                                                                   
commit 2f64de7dc9df58323db21b676251df27c46b924f                                                                                                                                                                                                                                              
Author: Gregory Nisbet <>                                                                                                                                                                                                                                            

    second commit                                                                                                                                                                                                                                                                            

diff --git a/bar b/bar                                                                                                                                                                                                                                                                       
new file mode 100644                                                                                                                                                                                                                                                                         
index 0000000..5716ca5                                                                                                                                                                                                                                                                       
--- /dev/null                                                                                                                                                                                                                                                                                
+++ b/bar                                                                                                                                                                                                                                                                                    
@@ -0,0 +1 @@                                                                                                                                                                                                                                                                                
+bar                                                                                                                                                                                                                                                                                         

$ git --no-pager show --format=short HEAD^                                                                                                                                                                                                                  
commit 5d9596507023a4af4dd7536e49e97359b35632d6                                                                                                                                                                                                                                              
Author: Gregory Nisbet <>                                                                                                                                                                                                                                            

    initial commit                                                                                                                                                                                                                                                                           

diff --git a/foo b/foo                                                                                                                                                                                                                                                                       
new file mode 100644                                                                                                                                                                                                                                                                         
index 0000000..257cc56                                                                                                                                                                                                                                                                       
--- /dev/null                                                                                                                                                                                                                                                                                
+++ b/foo                                                                                                                                                                                                                                                                                    
@@ -0,0 +1 @@                                                                                                                                                                                                                                                                                
+foo        

0 个答案:

没有答案