Chèn một cam kết trước khi cam kết gốc trong Git?


231

Tôi đã hỏi trước về cách làm sạch hai lần xác nhận đầu tiên trong kho git.

Mặc dù các giải pháp khá thú vị và không thực sự gây khó chịu như một số thứ khác trong git, nhưng chúng vẫn còn một chút tổn thương nếu bạn cần lặp lại quy trình nhiều lần trong quá trình phát triển dự án của mình.

Vì vậy, tôi chỉ muốn trải qua nỗi đau một lần, và sau đó có thể mãi mãi sử dụng rebase tương tác tiêu chuẩn.

Sau đó, điều tôi muốn làm là có một cam kết ban đầu trống rỗng chỉ tồn tại với mục đích là người đầu tiên. Không có mã, không có gì. Chỉ chiếm không gian để nó có thể là cơ sở cho rebase.

Câu hỏi của tôi là, có một kho lưu trữ hiện có, làm thế nào để tôi chèn một cam kết mới, trống trước cái đầu tiên và chuyển mọi người khác về phía trước?


3
;) Tôi đoán nó vẫn đảm bảo một câu trả lời. Tôi sắp xếp khám phá nhiều cách người ta có thể phát điên bằng cách chỉnh sửa lịch sử một cách ám ảnh. Đừng lo lắng, không phải là một kho lưu trữ được chia sẻ.
kch

11
Từ một biên tập viên lịch sử điên rồ, ám ảnh đến một người khác, cảm ơn vì đã đăng câu hỏi! ; D
Marco

10
Để bảo vệ @ kch, một lý do hoàn toàn chính đáng là một lý do mà tôi thấy mình: Thêm một ảnh chụp nhanh của một phiên bản lịch sử không bao giờ bị bắt trong repo.
McStopher cũ

4
Tôi có một lý do chính đáng khác! Thêm một cam kết trống trước lần đầu tiên để có thể khởi động lại cam kết đầu tiên và xóa
bloat

Câu trả lời:


314

Có 2 bước để đạt được điều này:

  1. Tạo một cam kết trống mới
  2. Viết lại lịch sử để bắt đầu từ cam kết trống này

Chúng tôi sẽ đặt cam kết trống mới trên một nhánh tạm thời newrootđể thuận tiện.

1. Tạo một cam kết trống mới

Có một số cách bạn có thể làm điều này.

Chỉ sử dụng hệ thống ống nước

Cách tiếp cận sạch nhất là sử dụng hệ thống ống nước của Git để chỉ cần tạo một cam kết trực tiếp, giúp tránh chạm vào bản sao làm việc hoặc chỉ mục hoặc chi nhánh nào được kiểm tra, v.v.

  1. Tạo một đối tượng cây cho một thư mục trống:

    tree=`git hash-object -wt tree --stdin < /dev/null`
    
  2. Bao bọc một cam kết xung quanh nó:

    commit=`git commit-tree -m 'root commit' $tree`
    
  3. Tạo một tham chiếu đến nó:

    git branch newroot $commit
    

Tất nhiên bạn có thể sắp xếp lại toàn bộ quy trình thành một lớp lót nếu bạn biết rõ vỏ của mình.

Không có hệ thống ống nước

Với các lệnh sứ thông thường, bạn không thể tạo một cam kết trống mà không kiểm tra newrootchi nhánh và cập nhật chỉ mục và bản sao làm việc nhiều lần, không có lý do chính đáng. Nhưng một số có thể thấy điều này dễ hiểu hơn:

git checkout --orphan newroot
git rm -rf .
git clean -fd
git commit --allow-empty -m 'root commit'

Lưu ý rằng trên các phiên bản Git rất cũ không có công --orphantắc checkout, bạn phải thay thế dòng đầu tiên bằng dòng này:

git symbolic-ref HEAD refs/heads/newroot

2. Viết lại lịch sử để bắt đầu từ cam kết trống này

Bạn có hai lựa chọn ở đây: đánh lại hoặc viết lại lịch sử sạch.

Nổi loạn

git rebase --onto newroot --root master

Điều này có đức tính đơn giản. Tuy nhiên, nó cũng sẽ cập nhật tên và ngày của người giao dịch trên mỗi lần xác nhận cuối cùng trên chi nhánh.

Ngoài ra, với một số lịch sử trường hợp cạnh, nó thậm chí có thể thất bại do xung đột hợp nhất - mặc dù thực tế là bạn đang phản đối một cam kết không chứa gì.

Lịch sử viết lại

Cách tiếp cận sạch hơn là viết lại chi nhánh. Không giống như git rebase, bạn sẽ cần tìm kiếm cam kết chi nhánh của bạn bắt đầu từ:

git replace <currentroot> --graft newroot
git filter-branch master

Việc viết lại xảy ra trong bước thứ hai, rõ ràng; đó là bước đầu tiên cần giải thích. Có gì git replacekhông là nó nói với Git rằng bất cứ khi nào nó thấy một tham chiếu đến một đối tượng mà bạn muốn thay thế, thay vì Git nên xem xét việc thay đổi của đối tượng đó.

Với công --grafttắc, bạn đang nói với nó một cái gì đó hơi khác so với bình thường. Bạn đang nói chưa có đối tượng thay thế, nhưng bạn muốn thay thế <currentroot>đối tượng cam kết bằng một bản sao chính xác của chính nó ngoại trừ (các) cam kết cha mẹ thay thế phải là một đối tượng mà bạn đã liệt kê (tức là newrootcam kết ). Sau đó git replacetiếp tục và tạo cam kết này cho bạn, và sau đó tuyên bố cam kết đó là thay thế cho cam kết ban đầu của bạn.

Bây giờ nếu bạn làm một git log, bạn sẽ thấy mọi thứ đã trông như bạn muốn: chi nhánh bắt đầu từ đó newroot.

Tuy nhiên, lưu ý rằng git replace không thực sự sửa đổi lịch sử - nó cũng không lan truyền ra khỏi kho lưu trữ của bạn. Nó chỉ thêm một chuyển hướng cục bộ vào kho lưu trữ của bạn từ đối tượng này sang đối tượng khác. Điều này có nghĩa là không ai khác thấy tác dụng của sự thay thế này - chỉ có bạn.

Đó là lý do tại sao filter-branchbước này là cần thiết. Với git replacebạn tạo một bản sao chính xác với các xác nhận gốc được điều chỉnh cho cam kết gốc; git filter-branchsau đó lặp lại quá trình này cho tất cả các cam kết sau đây. Đó là nơi lịch sử thực sự được viết lại để bạn có thể chia sẻ nó.


1
--onto newrootTùy chọn đó là dư thừa; bạn có thể làm mà không cần nó bởi vì đối số bạn vượt qua nó, newrootgiống như đối số ngược dòng - newroot.
wilmustell

7
Tại sao không sử dụng sứ thay vì lệnh ống nước?. Tôi sẽ thay thế git Symbolic-ref HEAD refs / Heads / newroot bằng git checkout
dạng newroot

4
@nenopera: vì câu trả lời này đã được viết trước khi git-checkoutcó công tắc đó. Tôi đã cập nhật nó để đề cập đến cách tiếp cận đó trước tiên, cảm ơn con trỏ.
Aristotle Pagaltzis

1
Nếu newroot của bạn không trống, hãy sử dụng git rebase --merge -s recursive -X theirs --onto newroot --root masterđể tự động giải quyết tất cả các xung đột (xem câu trả lời này ). @AlexanderKuzin
người dùng

1
@Geremia Bạn chỉ có thể sửa đổi cam kết cuối cùng, vì vậy nếu kho lưu trữ của bạn chỉ chứa cam kết gốc, nó có thể hoạt động, nếu không, bạn sẽ phải loại bỏ tất cả các cam kết khác trong repo trên đầu trang của cam kết gốc đã sửa đổi. Nhưng ngay cả khi đó, chủ đề ngụ ý rằng bạn không muốn thay đổi cam kết gốc, mà muốn chèn một cam kết khác trước gốc hiện có.
người dùng

30

Hợp nhất các câu trả lời của Aristotle Pagaltzis và Uwe Kleine-König và bình luận của Richard Bronosky.

git symbolic-ref HEAD refs/heads/newroot
git rm --cached -r .
git clean -f -d
# touch .gitignore && git add .gitignore # if necessary
git commit --allow-empty -m 'initial'
git rebase --onto newroot --root master
git branch -d newroot

(chỉ để mọi thứ ở một nơi)


Thật tuyệt vời. Sẽ thật tuyệt nếu đây có thể là những gì một git rebase -i --root đã làm trong nội bộ.
aredridel

Đúng, tôi đã rất ngạc nhiên khi biết rằng nó không.
Antony Hatchkins

Tôi đã phải thay đổi lệnh rebase thành git rebase newroot master, vì lỗi.
marbel82

@ antony-hatchkins cảm ơn vì điều này. Tôi có một repo git hiện có và (vì nhiều lý do mà tôi sẽ không tham gia ở đây) Tôi đang cố gắng nối thêm một cam kết git NON-EMPTY như là cam kết đầu tiên của tôi. Vì vậy, tôi đã thay thế git commit --allow-blank -m 'ban đầu' bằng git add .; git commit -m "cam kết ban đầu"; đẩy git; Và sau đó bước rebase này: git rebase --onto newroot --root master đang thất bại với TON các xung đột hợp nhất. Có lời khuyên nào không? : ((
kp123

@ kp123 hãy thử một cam kết trống :)
Antony Hatchkins

12

Tôi thích câu trả lời của Aristotle. Nhưng nhận thấy rằng đối với một kho lưu trữ lớn (> 5000 cam kết) nhánh bộ lọc hoạt động tốt hơn so với rebase vì một số lý do 1) nhanh hơn 2) nó không cần sự can thiệp của con người khi có xung đột hợp nhất. 3) nó có thể viết lại các thẻ - bảo quản chúng. Lưu ý rằng nhánh lọc hoạt động vì không có câu hỏi nào về nội dung của từng cam kết - nó hoàn toàn giống như trước 'rebase' này.

Các bước của tôi là:

# first you need a new empty branch; let's call it `newroot`
git symbolic-ref HEAD refs/heads/newroot
git rm --cached -r .
git clean -f -d

# then you apply the same steps
git commit --allow-empty -m 'root commit'

# then use filter-branch to rebase everything on newroot
git filter-branch --parent-filter 'sed "s/^\$/-p <sha of newroot>/"' --tag-name-filter cat master

Lưu ý rằng các tùy chọn '--tag-name-filter cat' có nghĩa là các thẻ sẽ được viết lại để trỏ đến các xác nhận mới được tạo.


Điều này không giúp tạo ra các cam kết không trống cũng là một trường hợp sử dụng thú vị.
ceztko

So với các giải pháp khác, của bạn chỉ có một tác dụng phụ không đáng kể: nó thay đổi băm, nhưng toàn bộ lịch sử vẫn chưa được xử lý. Cảm ơn bạn!
Vladyslav Savigan

5

Tôi đã sử dụng thành công câu trả lời của Aristotle và Kent:

# first you need a new empty branch; let's call it `newroot`
git checkout --orphan newroot
git rm -rf .
git commit --allow-empty -m 'root commit'
git filter-branch --parent-filter \
'sed "s/^\$/-p <sha of newroot>/"' --tag-name-filter cat -- --all
# clean up
git checkout master
git branch -D newroot
# make sure your branches are OK first before this...
git for-each-ref --format="%(refname)" refs/original/ | \
xargs -n 1 git update-ref -d

Điều này cũng sẽ viết lại tất cả các nhánh (không chỉ master) ngoài các thẻ.


dòng cuối cùng này làm gì?
Diederick C. Niehorster

Nó tìm kiếm thông qua refs/original/và xóa từng ref. Các ref mà nó xóa nên đã được tham chiếu bởi một số nhánh khác, vì vậy chúng không thực sự biến mất, chỉ cần refs/original/được gỡ bỏ.
ldav1s

Điều này làm việc cho tôi. Ngoài ra, tôi đã sử dụng timedatectl set-time '2017-01-01 00:00:00'để đưa ra newrootmột dấu thời gian cũ.
chrm

4

git rebase --root --onto $emptyrootcommit

nên làm thủ thuật dễ dàng


3
$emptyrootcommitlà một biến shell mà mở rộng thành không có gì, chắc chắn?
Flimm

@Flimm: $ blankrootcommit là sha1 của một cam kết trống mà poster ban đầu dường như đã có.
Uwe Kleine-König

4

Tôi nghĩ rằng sử dụng git replacegit filter-branchlà một giải pháp tốt hơn so với sử dụng git rebase:

  • hiệu suất tốt hơn
  • dễ dàng hơn và ít rủi ro hơn (bạn có thể xác minh kết quả của mình ở mỗi bước và hoàn tác những gì bạn đã làm ...)
  • làm việc tốt với nhiều chi nhánh với kết quả được đảm bảo

Ý tưởng đằng sau nó là:

  • Tạo một cam kết trống mới trong quá khứ
  • Thay thế cam kết gốc cũ bằng một cam kết chính xác tương tự ngoại trừ cam kết gốc mới được thêm vào dưới dạng cha mẹ
  • Xác minh rằng tất cả là như mong đợi và chạy git filter-branch
  • Một lần nữa, xác minh rằng tất cả đều ổn và xóa các tệp git không cần thiết nữa

Đây là một kịch bản cho 2 bước đầu tiên:

#!/bin/bash
root_commit_sha=$(git rev-list --max-parents=0 HEAD)
git checkout --force --orphan new-root
find . -path ./.git -prune -o -exec rm -rf {} \; 2> /dev/null
git add -A
GIT_COMMITTER_DATE="2000-01-01T12:00:00" git commit --date==2000-01-01T12:00:00 --allow-empty -m "empty root commit"
new_root_commit_sha=$(git rev-parse HEAD)

echo "The commit '$new_root_commit_sha' will be added before existing root commit '$root_commit_sha'..."

parent="parent $new_root_commit_sha"
replacement_commit=$(
 git cat-file commit $root_commit_sha | sed "s/author/$parent\nauthor/" |
 git hash-object -t commit -w --stdin
) || return 3
git replace "$root_commit_sha" "$replacement_commit"

Bạn có thể chạy tập lệnh này mà không gặp rủi ro (ngay cả khi thực hiện sao lưu trước khi thực hiện hành động mà bạn chưa từng làm trước đây là một ý tưởng hay;)) và nếu kết quả không như mong đợi, chỉ cần xóa các tệp được tạo trong thư mục .git/refs/replacevà thử lại; )

Khi bạn đã xác minh rằng trạng thái của kho lưu trữ là những gì bạn mong đợi, hãy chạy lệnh sau để cập nhật lịch sử của tất cả các chi nhánh :

git filter-branch -- --all

Bây giờ, bạn phải xem 2 lịch sử, lịch sử cũ và lịch sử mới (xem trợ giúp filter-branchđể biết thêm thông tin). Bạn có thể so sánh 2 và kiểm tra lại nếu tất cả đều ổn. Nếu bạn hài lòng, hãy xóa các tệp không cần thiết nữa:

rm -rf ./.git/refs/original
rm -rf ./.git/refs/replace

Bạn có thể quay lại masterchi nhánh của mình và xóa chi nhánh tạm thời:

git checkout master
git branch -D new-root

Bây giờ, tất cả nên được thực hiện;)


3

Tôi đã rất phấn khích và đã viết một phiên bản 'idempotent' của tập lệnh hay này ... nó sẽ luôn chèn cùng một cam kết trống và nếu bạn chạy nó hai lần, nó sẽ không thay đổi băm cam kết của bạn mỗi lần. Vì vậy, đây là ý kiến ​​của tôi về git-insert-blank-root :

#!/bin/sh -ev
# idempotence achieved!
tmp_branch=__tmp_empty_root
git symbolic-ref HEAD refs/heads/$tmp_branch
git rm --cached -r . || true
git clean -f -d
touch -d '1970-01-01 UTC' .
GIT_COMMITTER_DATE='1970-01-01T00:00:00 +0000' git commit \
  --date='1970-01-01T00:00:00 +0000' --allow-empty -m 'initial'
git rebase --committer-date-is-author-date --onto $tmp_branch --root master
git branch -d $tmp_branch

Có đáng để thêm phức tạp? có thể không, nhưng tôi sẽ sử dụng cái này

Điều này cũng cho phép thực hiện thao tác này trên một số bản sao của bản sao và kết quả tương tự, vì vậy chúng vẫn tương thích ... kiểm tra ... đúng vậy, hoạt động, nhưng cũng cần xóa và thêm điều khiển từ xa một lần nữa, ví dụ:

git remote rm origin
git remote add --track master user@host:path/to/repo

3

Để thêm một cam kết trống khi bắt đầu kho lưu trữ, nếu bạn quên tạo một cam kết trống ngay sau "git init":

git rebase --root --onto $(git commit-tree -m 'Initial commit (empty)' 4b825dc642cb6eb9a060e54bf8d69288fbee4904)

1
4b825dc ... là hàm băm của cây trống: stackoverflow.com/questions/9765453/ Lời
mrks

2

Vâng, đây là những gì tôi nghĩ ra:

# Just setting variables on top for clarity.
# Set this to the path to your original repository.
ORIGINAL_REPO=/path/to/original/repository

# Create a new repository…
mkdir fun
cd fun
git init
# …and add an initial empty commit to it
git commit --allow-empty -m "The first evil."

# Add the original repository as a remote
git remote add previous $ORIGINAL_REPO
git fetch previous

# Get the hash for the first commit in the original repository
FIRST=`git log previous/master --pretty=format:%H  --reverse | head -1`
# Cherry-pick it
git cherry-pick $FIRST
# Then rebase the remainder of the original branch on top of the newly 
# cherry-picked, previously first commit, which is happily the second 
# on this branch, right after the empty one.
git rebase --onto master master previous/master

# rebase --onto leaves your head detached, I don't really know why)
# So now you overwrite your master branch with the newly rebased tree.
# You're now kinda done.
git branch -f master
git checkout master
# But do clean up: remove the remote, you don't need it anymore
git remote rm previous

2

Đây là bashkịch bản của tôi dựa trên câu trả lời của Kent với những cải tiến:

  • nó kiểm tra chi nhánh ban đầu, không chỉ masterkhi hoàn thành;
  • Tôi đã cố gắng tránh nhánh tạm thời, nhưng git checkout --orphanchỉ hoạt động với một nhánh, không tách rời trạng thái đầu, vì vậy nó đã được kiểm tra đủ lâu để thực hiện cam kết gốc mới và sau đó xóa;
  • nó sử dụng hàm băm của cam kết gốc mới trong filter-branch(Kent để lại một trình giữ chỗ trong đó để thay thế thủ công);
  • Các filter-branchhoạt động chỉ viết lại các chi nhánh địa phương, không từ xa quá
  • siêu dữ liệu tác giả và committer được chuẩn hóa để cam kết gốc giống hệt nhau trên các kho lưu trữ.

#!/bin/bash

# Save the current branch so we can check it out again later
INITIAL_BRANCH=`git symbolic-ref --short HEAD`
TEMP_BRANCH='newroot'

# Create a new temporary branch at a new root, and remove everything from the tree
git checkout --orphan "$TEMP_BRANCH"
git rm -rf .

# Commit this empty state with generic metadata that will not change - this should result in the same commit hash every time
export GIT_AUTHOR_NAME='nobody'
export GIT_AUTHOR_EMAIL='nobody@example.org'
export GIT_AUTHOR_DATE='2000-01-01T00:00:00+0000'
export GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"
export GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"
export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
git commit --allow-empty -m 'empty root'
NEWROOT=`git rev-parse HEAD`

# Check out the commit we just made and delete the temporary branch
git checkout --detach "$NEWROOT"
git branch -D "$TEMP_BRANCH"

# Rewrite all the local branches to insert the new root commit, delete the 
# original/* branches left behind, and check out the rewritten initial branch
git filter-branch --parent-filter "sed \"s/^\$/-p $NEWROOT/\"" --tag-name-filter cat -- --branches
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
git checkout "$INITIAL_BRANCH"

2

Để chuyển đổi cam kết gốc:

Đầu tiên, tạo cam kết bạn muốn là đầu tiên.

Thứ hai, chuyển đổi thứ tự của các cam kết bằng cách sử dụng:

git rebase -i --root

Một trình soạn thảo sẽ xuất hiện với các xác nhận cho đến khi xác nhận gốc, như:

chọn 1234 tin nhắn gốc cũ

chọn 0294 Một cam kết ở giữa

chọn 5678 cam kết bạn muốn đặt ở gốc

Sau đó, bạn có thể đặt cam kết bạn muốn lên đầu tiên, bằng cách đặt nó vào dòng đầu tiên. Trong ví dụ:

chọn 5678 cam kết bạn muốn đặt ở gốc

chọn 1234 tin nhắn gốc cũ

chọn 0294 Một cam kết ở giữa

Thoát khỏi trình soạn thảo, thứ tự cam kết sẽ thay đổi.

PS: Để thay đổi trình chỉnh sửa git sử dụng, hãy chạy:

git config - lõi cốt lõi.editor name_of_the_editor_program_you_want_to_use


1
Bây giờ rebase đã có --root, đây là giải pháp gọn gàng nhất.
Ross Burton

1

Kết hợp mới nhất và lớn nhất. Không có tác dụng phụ, không có xung đột, giữ thẻ.

git log --reverse

tree=`git hash-object -wt tree --stdin < /dev/null`
commit=`git commit-tree -m 'Initialize empty repository' $tree`
echo $commit # copy below, interpolation didn't work for me

git filter-branch --parent-filter 'sed "s/^\$/-p <commit>/"' --tag-name-filter cat master

git log --reverse

Lưu ý rằng trên GitHub, bạn sẽ mất dữ liệu chạy CI và PR có thể bị rối trừ khi các nhánh khác cũng được sửa.


0

Theo câu trả lời Aristotle Pagaltzis và những người khác nhưng sử dụng các lệnh đơn giản hơn

zsh% git checkout --orphan empty     
Switched to a new branch 'empty'
zsh% git rm --cached -r .
zsh% git clean -fdx
zsh% git commit --allow-empty -m 'initial empty commit'
[empty (root-commit) 64ea894] initial empty commit
zsh% git checkout master
Switched to branch 'master'
zsh% git rebase empty
First, rewinding head to replay your work on top of it...
zsh% git branch -d empty 
Deleted branch empty (was 64ea894).

Lưu ý rằng repo của bạn không nên chứa các sửa đổi cục bộ đang chờ được cam kết.
Lưu ý git checkout --orphansẽ hoạt động ở các phiên bản mới của git, tôi đoán vậy.
Lưu ý hầu hết thời gian git statuscho gợi ý hữu ích.


-6

Bắt đầu một kho lưu trữ mới.

Đặt ngày của bạn trở lại ngày bắt đầu bạn muốn.

Làm mọi thứ theo cách bạn muốn bạn đã làm, điều chỉnh thời gian hệ thống để phản ánh khi bạn muốn bạn làm theo cách đó. Kéo các tệp từ kho lưu trữ hiện có khi cần thiết để tránh rất nhiều thao tác gõ không cần thiết.

Khi bạn đến ngày hôm nay, trao đổi các kho lưu trữ và bạn đã hoàn tất.

Nếu bạn chỉ điên (thành lập) nhưng thông minh hợp lý (có thể, bởi vì bạn phải có một số lượng thông minh nhất định để nghĩ ra những ý tưởng điên rồ như thế này), bạn sẽ viết kịch bản cho quá trình.

Điều đó cũng sẽ làm cho nó đẹp hơn khi bạn quyết định rằng bạn muốn quá khứ đã xảy ra theo cách khác một tuần kể từ bây giờ.


Tôi có cảm giác xấu về một giải pháp đòi hỏi bạn phải loay hoay với ngày hệ thống, nhưng bạn đã cho tôi một ý tưởng, mà tôi đã phát triển một chút và, than ôi, nó đã hoạt động. Vì vậy, cảm ơn.
kch

-7

Tôi biết bài đăng này đã cũ nhưng trang này là trang đầu tiên khi Google "chèn cam kết git".

Tại sao làm cho những điều đơn giản trở nên phức tạp?

Bạn có ABC và bạn muốn ABZC.

  1. git rebase -i trunk (hoặc bất cứ điều gì trước B)
  2. thay đổi chọn để chỉnh sửa trên dòng B
  3. thực hiện các thay đổi của bạn: git add ..
  4. git commit( git commit --amendsẽ chỉnh sửa B và không tạo Z)

[Bạn có thể làm bao nhiêu git commit tùy ý ở đây để chèn thêm các xác nhận. Tất nhiên, bạn có thể gặp rắc rối với bước 5, nhưng giải quyết xung đột sáp nhập với git là một kỹ năng bạn nên có. Nếu không, hãy luyện tập!]

  1. git rebase --continue

Đơn giản phải không?

Nếu bạn hiểu git rebase, việc thêm một cam kết 'root' không phải là một vấn đề.

Hãy vui vẻ với git!


5
Câu hỏi yêu cầu chèn một cam kết đầu tiên : từ ABC bạn muốn ZABC. Một cách đơn giản git rebasekhông thể làm điều này.
Petr Viktorin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.