簡體   English   中英

git 日志歷史簡化

[英]git log history simplification

假設我有以下歷史

        D---E-------F
       /     \       \
      B---C---G---H---I---J
     /                     \
    A-------K---------------L--M

git log --ancestry-path D..M 會給我

            E-------F
             \       \
              G---H---I---J
                           \
                            L--M

但是,我只想要以下內容

            E
             \       
              G---H---I---J
                           \
                            L--M

或者

            E-------F
                     \
                      I---J
                           \
                            L--M

本質上,我只想遍歷一條路徑,而不是兩條。

這可能嗎? 如果是這樣,命令是什么?

編輯:

我試過使用--first-parent,但這不完全是。 git 日志 --first-parent G..M 給我

                    F
                     \
                  H---I---J
                           \
                            L--M

它包括 F,因為 F 是 I 的第一個父母。相反,我想

                  H---I---J
                           \
                            L--M

任何幫助,將不勝感激

解決方案(對我有用):

正如@VonC 所說,沒有一個單線可以做到這一點。 所以我最終使用了 bash 腳本。

  1. 對於“git log --ancestry-path G..M”中的每個提交
  2. 確定 $commit 的父級是否包含我們之前的提交
  3. 如果是,請繼續。 做一些有趣的事情。
  4. 如果不是,請跳過該提交。

例如,git log --first-commit G..M 是

H - F - I - J - L - M

然而,F 的父母是 E,而不是 H。所以我們省略 F,給我

H - I - J - L - M

耶!

我不認為這是直接可能的(除非您事先知道要包含/排除的確切列表,這否定了走 DAG 的目的)

實際上, OP Ken Hirakawa通過以下方式獲得了預期的線性歷史:

git log --pretty=format:"%h%n" --ancestry-path --reverse $prev_commit..$end_commit

對於每個提交,確保它是前一個提交的直接子級。

這是平川健寫的劇本


這是我的腳本,用於創建 git 日志手冊頁的歷史簡化部分中提到的 DAG,用於--ancestry-path

你會在最后找到我用來創建類似歷史記錄的 bash 腳本(使用根目錄的名稱和您的用戶名調用它)。

我定義:

$ git config --global alias.lgg "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative"

我得到:

$ git lgg
* d7c4459 - (HEAD, M, fromA) M <VonC>
*   82b011d - (L) Merge commit 'J' into fromA <VonC>
|\
| * 190265b - (J, master) J <VonC>
| *   ef8e325 - (I) Merge commit 'F' <VonC>
| |\
| | * 4b6d976 - (F, fromB) F <VonC>
| * | 45a5d4d - (H) H <VonC>
| * |   834b239 - (G) Merge commit 'E' <VonC>
| |\ \
| | |/
| | * f8e9272 - (E) E <VonC>
| | * 96b5538 - (D) D <VonC>
| * | 49eff7f - (C) C <VonC>
| |/
| * 02c3ef4 - (B) B <VonC>
* | c0d9e1e - (K) K <VonC>
|/
* 6530d79 - (A) A <VonC>

從那里,我不能排除提交 I 的父母之一。

祖先路徑確實返回:

$ git lgg --ancestry-path D..M
* d7c4459 - (HEAD, M, fromA) M <VonC>
* 82b011d - (L) Merge commit 'J' into fromA <VonC>
* 190265b - (J, master) J <VonC>
*   ef8e325 - (I) Merge commit 'F' <VonC>
|\
| * 4b6d976 - (F, fromB) F <VonC>
* | 45a5d4d - (H) H <VonC>
* | 834b239 - (G) Merge commit 'E' <VonC>
|/
* f8e9272 - (E) E <VonC>

這與日志手冊頁一致:

常規D..M計算作為M祖先的提交集,但不包括作為D祖先的提交。
這有助於了解自D以來導致M的歷史發生了什么,從某種意義上說,“ M有什么在D中不存在”。
此示例中的結果將是所有提交,除了AB (當然還有D本身)。

但是,當我們想找出M中的哪些提交被D引入的錯誤污染並需要修復時,我們可能只想查看D..M實際上是D后代的子集,即不包括CK
這正是--ancestry-path選項的作用。


#!/bin/bash

function makeCommit() {
  local letter=$1
  if [[ `git tag -l $letter` == "" ]] ; then
    echo $letter > $root/$letter
    git add .
    git commit -m "${letter}"
    git tag -m "${letter}" $letter
  else
    echo "commit $letter already there"
  fi
}

function makeMerge() {
  local letter=$1
  local from=$2
  if [[ `git tag -l $letter` == "" ]] ; then
    git merge $from
    git tag -m "${letter}" $letter
  else
    echo "merge $letter already done"
  fi
}

function makeBranch() {
  local branch=$1
  local from=$2
  if [[ "$(git branch|grep $1)" == "" ]] ; then
    git checkout -b $branch $from
  else
    echo "branch $branch already created"
    git checkout $branch
  fi
}

root=$1
user=$2
if [[ ! -e $root/.git ]] ; then
  git init $root
fi
export GIT_WORK_TREE="./$root"
export GIT_DIR="./$root/.git"
git config --local user.name $2

makeCommit "A"
makeCommit "B"
makeCommit "C"
makeBranch "fromB" "B"
makeCommit "D"
makeCommit "E"
makeCommit "F"
git checkout master
makeMerge "G" "E"
makeCommit "H"
makeMerge "I" "F"
makeCommit "J"
makeBranch "fromA" "A"
makeCommit "K"
makeMerge "L" "J"
makeCommit "M"

我不得不承認我不理解您的解決方案-它不適用於我的示例-但是如果我正確理解了您的用例(給定一對提交,您需要它們之間的任意線性路徑,沒有拆分) ,我有同樣的問題,以下解決方案似乎有效:

  • 使用 --ancestry-path 運行日志,並確保記下每個提交的子項
  • 遍歷結果,跟蹤“最后一個接受的孩子”,並在每次提交引用一個接受的孩子時更新它(或者還沒有接受的孩子——初始情況)
  • 實際上以某種有用的方式打印生成的“已接受”條目

生成的腳本如下所示:

#!/bin/bash
output_set=""; child_to_match=""; # init
while read -r; do
  if { [ -n "$REPLY" ]; } && { [[ "${REPLY:41}" =~ "$child_to_match" ]] || [ -z "$child_to_match" ]; }; then
    child_to_match=${REPLY:0:40}
    output_set="$output_set $child_to_match"
  fi
done <<<  "$(git rev-list --ancestry-path --children $1)"
if [[ -n $output_set ]]; then
  git show -s $output_set "${@:2}"
fi

It can be called like single-ancestry-path.sh RANGE_EXPRESSION DECORATION_ARGS , supporting generally the same decoration arguments as git log (it is in fact git show , being called once per commit), so taking the famous lg2 example from https:// stackoverflow.com/a/9074343/74296 ,調用可能如下所示:例如:

single-ancestry-path.sh master..MyBranch --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'

已經 9 年了,所以我希望有一個更簡單的答案,但我找不到。

我也不喜歡合並帶來的問題,並且已經放棄了在我的主流歷史中出現的問題。 每當有一個大的合並到一個主分支上時,我都會用相同的內容重新提交它,但作為一個單一的提交。

 D---E--------F Co-Developer / B---C---G'---H---I'--J Team Leader / A-------K----------------L'--M Main Stream

在這里,G'、I' 和 L' 將是我重新提交合並結果的點。 分支描述只是描述了我可以可視化發生的問題樹的場景。 因此,G 和 G'(類似於 I 和 I')的內容將是相同的,團隊負責人已合並到開發人員的最新工作中。 和 L' 一樣,L 的特點融入了主流。

I totally understand that avoiding a problem is not the same as solving it, and sympathize with those facing the problem now.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM