71470


以下のような git のコミット履歴があります。

＜現状＞

[code]

     * ローカルコミット7 
     * ローカルコミット6
     * ローカルコミット5
     * マージ
     |\  
     | * リモートコミット3 
     | * リモートコミット2
     | * リモートコミット1
     | | 
     * | ローカルコミット4
     * | ローカルコミット3
     * | ローカルコミット2
     | |
     |/  
     |  
     * ローカルコミット1
     |  
     ...
    
    
[/code]

`git log` を見やすくする目的で、以下の＜A＞もしくは＜B＞のようにコミットをまとめたいと考えています。どのようにすればいいでしょうか。

＜A＞

[code]

     * マージ+ローカルコミット5〜7 
     |\  
     | * リモートコミット3 
     | * リモートコミット2
     | * リモートコミット1
     | | 
     * | ローカルコミット2〜4
     | |
     |/  
     |  
     * ローカルコミット1
     |  
     ...
    
    
[/code]

＜B＞

[code]

     * マージ+ローカルコミット2〜7 
     |\  
     | * リモートコミット3 
     | * リモートコミット2
     | * リモートコミット1
     | | 
     | |
     |/  
     |  
     * ローカルコミット1
     |  
     ...
    
    
[/code]

ポイントは以下の2点になります。

  * `git log --graph` の表示上に「”ローカルコミット4"と"リモートコミット3"をマージした」という記録を残した上で、"マージ" から "リモートコミット7" までを一つのコミットにまとめたい
  * ”ローカルコミット4"と"リモートコミット3"をマージした際に行ったコンフリクト解消のための手作業を、再度行わずに"ローカルコミット2"から"ローカルコミット4"をまとめたい

なにか方法はあるでしょうか。


CC BY-SA 4.0
2020-10-15T06:19:36.817
71214
2020-10-24T02:24:42.393
2020-10-15T08:33:40.887
28998
28998
question
git
gitのマージを含むコミット履歴の整理


`gite rebase`の [`--rebase-merges`(`-r`) オプション](https://git-scm.com/docs/git-
rebase#Documentation/git-rebase.txt--r)が利用可能かと思います。

* * *

### 初期設定

初期リポジトリを作成します:

[code]

    #!/bin/bash
    set -eu
    
    git init
    git commit --allow-empty -m init
    
    git checkout -b local-branch
    for i in {1..4} ; do
      git commit --allow-empty -m "ローカルコミット${i}"
    done
    
    git checkout @~3
    git checkout -b remote-branch
    for i in {1..3} ; do
      git commit --allow-empty -m "リモートコミット${i}"
    done
    
    git checkout local-branch
    git merge --no-edit remote-branch
    
    for i in {5..7} ; do
      git commit --allow-empty -m "ローカルコミット${i}"
    done
    
[/code]

上記のスクリプトを実行すると次のような状態になります(`git log --graph --pretty=format:"%h %s"`):

[code]

    * a231d0e ローカルコミット7
    * 54dccc9 ローカルコミット6
    * 28345fa ローカルコミット5
    *   19e3401 Merge branch 'remote-branch' into local-branch
    |\
    | * 6a1cdf4 リモートコミット3
    | * cbf2e5a リモートコミット2
    | * ecf9ddf リモートコミット1
    * | 1cecd54 ローカルコミット4
    * | 44c9adf ローカルコミット3
    * | 662d8d5 ローカルコミット2
    |/
    * f40cad8 ローカルコミット1
    * 35a78cc init
    
[/code]

このリポジトリを、質問文中にある[A], [B]それぞれの状態に変更します。  
`git rebase -i -r master` を実行すると、次のように表示されます:

[code]

    label onto
    
    # Branch remote-branch
    reset onto
    pick f40cad8 ローカルコミット1 # empty
    label branch-point
    pick ecf9ddf リモートコミット1 # empty
    pick cbf2e5a リモートコミット2 # empty
    pick 6a1cdf4 リモートコミット3 # empty
    label remote-branch
    
    reset branch-point # ローカルコミット1
    pick 662d8d5 ローカルコミット2 # empty
    pick 44c9adf ローカルコミット3 # empty
    pick 1cecd54 ローカルコミット4 # empty
    merge -C 19e3401 remote-branch # Merge branch 'remote-branch' into local-branch
    pick 28345fa ローカルコミット5 # empty
    pick 54dccc9 ローカルコミット6 # empty
    pick a231d0e ローカルコミット7 # empty
    
[/code]

* * *

### [A]へrebaseする

ローカルコミット3, 4をsquashしてローカルコミット2にまとめます。  
同様に、ローカルコミット5,6,7をmergeコミットにまとめます。

[code]

    label onto
    
    # Branch remote-branch
    reset onto
    pick f40cad8 ローカルコミット1 # empty
    label branch-point
    pick ecf9ddf リモートコミット1 # empty
    pick cbf2e5a リモートコミット2 # empty
    pick 6a1cdf4 リモートコミット3 # empty
    label remote-branch
    
    reset branch-point # ローカルコミット1
    pick 662d8d5 ローカルコミット2 # empty
    s 44c9adf ローカルコミット3 # empty
    s 1cecd54 ローカルコミット4 # empty
    merge -C 19e3401 remote-branch # Merge branch 'remote-branch' into local-branch
    s 28345fa ローカルコミット5 # empty
    s 54dccc9 ローカルコミット6 # empty
    s a231d0e ローカルコミット7 # empty
    
[/code]

結果:

[code]

    *   3494c34 Merge branch 'remote-branch' into local-branch ローカルコミット5 ローカルコミット6 ローカルコミット7
    |\
    | * 6a1cdf4 リモートコミット3
    | * cbf2e5a リモートコミット2
    | * ecf9ddf リモートコミット1
    * | 7b17503 ローカルコミット2 ローカルコミット3 ローカルコミット4
    |/
    * f40cad8 ローカルコミット1
    * 35a78cc init
    
[/code]

* * *

### [B]へrebaseする

mergeコミットをローカルコミット2の前に持ってきたうえで、ローカルコミット2-7をmergeコミットにsquashすればよいです。

[code]

    label onto
    
    # Branch remote-branch
    reset onto
    pick f40cad8 ローカルコミット1 # empty
    label branch-point
    pick ecf9ddf リモートコミット1 # empty
    pick cbf2e5a リモートコミット2 # empty
    pick 6a1cdf4 リモートコミット3 # empty
    label remote-branch
    
    reset branch-point # ローカルコミット1
    merge -C 19e3401 remote-branch # Merge branch 'remote-branch' into local-branch
    s 662d8d5 ローカルコミット2 # empty
    s 44c9adf ローカルコミット3 # empty
    s 1cecd54 ローカルコミット4 # empty
    s 28345fa ローカルコミット5 # empty
    s 54dccc9 ローカルコミット6 # empty
    s a231d0e ローカルコミット7 # empty
    
[/code]

結果:

[code]

    *   4dc1987 Merge branch 'remote-branch' into local-branch ローカルコミット2 ローカルコミット3 ローカルコミット4 ローカルコミット5 ローカルコミット6 ローカルコミット7
    |\
    | * 6a1cdf4 リモートコミット3
    | * cbf2e5a リモートコミット2
    | * ecf9ddf リモートコミット1
    |/
    * f40cad8 ローカルコミット1
    * 35a78cc init
    
[/code]

* * *

### 補足

ただし、[A],[B]ともにmergeコミットでマージ以外のことも行う結果になります。  
通常このようなrebaseは行うべきではないです。  
(一般的には、logグラフが複雑であることよりもmergeコミットでマージ以外のことが行われていることの方が理解するのに時間がかかる)

今回の質問文のブランチへの対応として最も適切なのは、単純にリモートコミット(リモートブランチ)に対してrebaseすることだと考えます:

[code]

    git checkout ローカルブランチ
    git rebase リモートブランチ
    
[/code]


CC BY-SA 4.0
2020-10-24T01:29:30.257
71470
2020-10-24T02:24:42.393
2020-10-24T02:24:42.393
2808
2808
71214
answer