Chuyển nhánh Git mà không cần kiểm tra tệp


100

Trong Git có thể chuyển sang một nhánh khác mà không cần kiểm tra tất cả các tệp không?

Sau khi chuyển đổi nhánh, tôi cần xóa tất cả các tệp, tạo lại chúng, cam kết và chuyển lại. Vì vậy, kiểm tra các tệp chỉ là một sự lãng phí thời gian (và có khoảng 14.000 tệp - đó là một hoạt động dài).

Để làm cho mọi thứ rõ ràng:

Tôi cần tất cả những thứ này để tải tài liệu lên GitHub.

Tôi có một kho lưu trữ với chi nhánh gh-pages . Khi tôi xây dựng lại tài liệu cục bộ, tôi sao chép nó vào thư mục kho lưu trữ, cam kết và đẩy lên GitHub. Nhưng tôi không hài lòng vì tôi có hai bản sao tài liệu tại địa phương. Và tôi quyết định tạo một nhánh trống và sau khi cam kết, chuyển sang trống và xóa các tệp. Nhưng chuyển đổi lại là một hoạt động lâu dài - vì vậy tôi đã hỏi câu hỏi này.

Tôi biết rằng tôi có thể rời khỏi nhánh gh-pages và xóa các tệp tin, nhưng tôi không thích cây làm việc bẩn thỉu.


"Dài" đối với bạn là bao lâu? Bạn đang làm việc trên nền tảng nào? Bạn có đang làm việc qua mạng chẳng hạn như với NFS hoặc chia sẻ tệp khác không?
Greg Hewgill

Mục đích của bài tập này là gì? Bạn có muốn có hai nhánh, một với cam kết chi tiết, thứ hai chỉ ghi lại những thay đổi lớn (chi tiết thô)?
Jakub Narębski

Có lẽ sẽ rẻ hơn nếu tạo một bản sao tạm thời (hoặc vĩnh viễn?) Của bản sao làm việc của bạn. Câu trả lời có liên quan của tôi và một writeup chương trình này hoạt động như thế nào ngay cả khi một thư mục con của kho chính.
krlmlr

Câu trả lời:


106

Có, bạn có thể làm điều này.

git symbolic-ref HEAD refs/heads/otherbranch

Nếu bạn cần phải cam kết trên nhánh này, bạn cũng sẽ muốn đặt lại chỉ mục nếu không, bạn sẽ phải cam kết một cái gì đó dựa trên nhánh đã kiểm tra cuối cùng.

git reset

1
Sử dụng echo "ebff34ffb665de0694872dceabe0edeaf50ec5a9" > .git/HEADtheo sau git resetđể trỏ đến một ref thay vì một nhánh.
cadorn

1
Việc ghi trực tiếp vào tệp HEAD ít đáng tin cậy hơn. Nếu bạn đang ở trong một tiểu khu thì sao? Đối với đầu tách rời (đầu trỏ trực tiếp đến SHA1), hãy thử điều này: git update-ref HEAD refs/heads/otherbranch
Alexander Bird

2
Nếu bạn muốn kiểm tra đến một chi nhánh tươi từ các chi nhánh hiện nay, một cách khác để làm điều này là 1. git stash2. git checkout -b otherBranch3.git stash pop
Winny

@AlexanderBird: git update-refhữu ích, nhưng nó cũng di chuyển phần chóp của nhánh hiện tại.
tomekwi

47

Chỉ sử dụng các lệnh git cơ bản:

Câu trả lời này dài hơn một chút so với câu trả lời của Charles, nhưng nó chỉ bao gồm các lệnh git cơ bản mà tôi có thể hiểu và do đó ghi nhớ, loại bỏ sự cần thiết phải tiếp tục tra cứu.

Đánh dấu vị trí hiện tại của bạn (cam kết trước nếu cần):

git checkout -b temp

Đặt lại (di chuyển) điểm đánh dấu sang nhánh khác mà không thay đổi dir đang hoạt động:

git reset <branch where you want to go>

bây giờ tạm thời và nhánh khác trỏ đến cùng một cam kết và dir làm việc của bạn không bị ảnh hưởng.

git checkout <branch where you want to go>

vì HEAD của bạn đã trỏ đến cùng một cam kết, nên dir đang hoạt động không được chạm vào

git branch -d temp

Lưu ý rằng các lệnh này cũng có sẵn từ bất kỳ ứng dụng khách đồ họa nào.


7
Tôi muốn git reset --soft <branch where you want to go>tránh cập nhật chỉ mục
JoelFan

7
Tôi đồng ý với chiến lược của bạn là tránh các lệnh của hệ thống ống nước git và ưu tiên các đường ống bằng sứ.
user64141,

26

Trong v2.24 git switchlà một cái gì đó giống như một cái két sắt git checkout.
Do đó tôi đổi tên bí danh dưới đây để git hopcho
"hop trên cành mà không thay đổi worktree"

Vì lợi ích của người đọc:

Mặc dù tôi nghĩ rằng giải pháp của Charles Bailey là một giải pháp chính xác, nhưng giải pháp này cần một sự điều chỉnh khi chuyển sang một thứ gì đó không phải là nhánh cục bộ. Ngoài ra, cần có một số cách thực hiện với các lệnh thông thường dễ hiểu. Đây là những gì tôi nghĩ ra:

git checkout --detach
git reset --soft commitish
git checkout commitish

Giải thích:

  • git checkout --detachcũng giống như git checkout HEAD^{}việc bỏ nhánh hiện tại phía sau và chuyển sang "trạng thái nguyên thủ tách rời". Vì vậy, sửa đổi tiếp theo của HEADkhông ảnh hưởng đến bất kỳ nhánh nào. Việc tách HEADra không ảnh hưởng đến worktree cũng như chỉ mục.
  • git reset --soft commitishsau đó di chuyển HEADđến SHA của đã cho commitish. Nếu bạn cũng muốn cập nhật chỉ mục, hãy bỏ --softđi, nhưng tôi không khuyên bạn nên làm như vậy. Điều này, một lần nữa, không chạm vào worktree và ( --soft) không phải là chỉ mục.
  • git checkout commitishsau đó lại gắn HEADvào commitish(nhánh) đã cho. (Nếu commitishlà SHA thì không có gì xảy ra.) Điều này cũng không ảnh hưởng đến chỉ mục cũng như worktree.

Giải pháp này chấp nhận mọi thứ đề cập đến một cam kết, vì vậy đây là lý tưởng cho một số gitbí danh. Dưới rev-parseđây chỉ là một bài kiểm tra để đảm bảo rằng không có gì bị hỏng trong chuỗi, sao cho lỗi chính tả không vô tình chuyển sang trạng thái đầu tách rời (khôi phục lỗi sẽ phức tạp hơn nhiều).

Điều này dẫn đến git hop treeishbí danh sau :

git config --global alias.hop '!f() { git rev-parse --verify "$*" && git checkout "HEAD^{}" && git reset --soft "$*" && git checkout "$*"; }; f'

FYI, bạn có thể tìm thấy nó trong danh sách gitbí danh của tôi .


Bạn không muốn sử dụng $@hơn là $*? Sự khác biệt là $ @ với các đối số được trích dẫn không mở rộng, có khoảng trắng bên trong.
kyb

1
@kyb Thủ thuật chức năng bị đánh cắp từ một câu trả lời SO khác . Và chắc chắn $@không có nghĩa ở đây. $*được sử dụng thay vì $1, như vậy git switch -f btrở thành giống như git switch '-f b'một lỗi. Bằng cách này, tôi có thể rút ngắn thời bí danh bằng cách rời đi một số xử lý lỗi như!f() { [ 1 = $# ] || { echo 'WTF!'; return 1; }; ..
Tino

Giải pháp rất tốt. Đặc biệt, nó có thể được sử dụng cho các chi nhánh ở xa!
Nils-o-mat

14

Sẽ không phải là một giải pháp tốt hơn để có hai thư mục làm việc (hai khu vực làm việc) với một kho lưu trữ, hoặc thậm chí hai kho lưu trữ?

Có công cụ git-new-workdir trong contrib/phần để giúp bạn điều này.


Git-new-workdir có giống với lệnh worktree của riêng git không? Tôi sử dụng worktree khi tôi muốn chuyển một nhánh vào một thư mục khác (mà không cần phải sao chép toàn bộ repo).
Ryuu

Tập git-new-worktreelệnh đặt trước git worktreelệnh con; lệnh này không khả dụng khi câu trả lời được viết. Ví dụ: tập lệnh yêu cầu hỗ trợ liên kết biểu tượng; IMHO tốt hơn là sử dụng hỗ trợ gốc.
Jakub Narębski

8

Tôi nghĩ bạn đang tìm kiếm lệnh sửa ống nước git read-tree. Thao tác này sẽ cập nhật chỉ mục nhưng sẽ không cập nhật bất kỳ tệp nào trong thư mục làm việc của bạn. Ví dụ, giả sử branchlà tên của nhánh cần đọc:

git read-tree cành

Nếu bạn muốn sau đó cam kết với nhánh bạn vừa đọc, bạn cũng sẽ cần:

git Symbol-ref HEAD refs / heads / branch

không Tôi chỉ cần đến chi nhánh công tắc, không có bất kỳ thay đổi khác - vì vậy mang tính biểu tượng-ref là đủ tốt
tig

read-treetạo ra các lỗi: fatal: Not a valid object name branchnếu không có bất kỳ git switch branchchưa
Andry

7

Bạn có thể ghi đè tệp HEAD của mình bằng một tên nhánh khác:

echo "ref: refs / heads / MyOtherBranch"> .git / HEAD


13
Đây có thể là tốt hơn để sử dụng lệnh symbolic-ref để làm điều này cho bạn: git symbolic-ref HEAD refs/heads/MyOtherBranch kernel.org/pub/software/scm/git/docs/git-symbolic-ref.html
Greg Hewgill

@GregHewgill, đây là cách duy nhất tôi biết để chuyển HEAD sang một hàm băm cam kết. Bạn có thể làm điều đó với git symbolic-ref?
tomekwi

0

Với quá nhiều tệp, tốt nhất bạn có thể chỉ giữ hai repo, một repo cho mỗi nhánh. Bạn có thể kéo các thay đổi qua lại nếu cần. Điều này sẽ ít gây ngạc nhiên hơn so với việc cố gắng chơi trò scurvy với git.


Bạn có thể sử dụng git-new-worktreecho rằng thay vì (trong contrib/)
Jakub Narębski

Tôi thường làm điều gì đó tương tự, đó là sao chép thư mục cục bộ của mình trước khi thực hiện bất kỳ "thứ git đáng sợ nào" với tư cách là người mới (như thay đổi chi nhánh, v.v.). Tôi khuyến khích mọi người đi theo con đường đó cho đến khi bạn cảm thấy tự tin vào git-fu của mình, nhưng hãy tránh xa nó khi có thể. Giữ hai repo riêng biệt là được, nhưng thêm một lớp phức tạp và không cho phép bạn tận dụng nhiều tính năng hữu ích của git (hợp nhất, chọn anh đào, v.v.).
David

0

Nếu bạn chỉ đơn giản là cố gắng thay đổi nơi mà một nhánh từ xa trỏ đến, bạn có thể làm điều đó với "git push" mà không cần chạm vào bản sao cục bộ của bạn.

http://kernel.org/pub/software/scm/git/docs/git-push.html

Định dạng của tham số <refspec> là một dấu cộng + tùy chọn, theo sau là ref nguồn <src>, theo sau là dấu hai chấm:, theo sau là ref <dst> đích. Nó được sử dụng để chỉ định đối tượng <src> mà ref <dst> trong kho lưu trữ từ xa sẽ được cập nhật.

Ví dụ: để cập nhật foo để cam kết c5f7eba, hãy làm như sau:

git push origin c5f7eba:foo

Không chắc liệu đó có phải là những gì bạn đang theo đuổi hay không.


Câu hỏi đã có câu trả lời: stackoverflow.com/questions/1282639/…
tig

0

bạn có thể tận dụng

      1. git checkout -f <new-branch>
      2. git cherry-pick -x <previous-branch-commit-id>

before-branch-commit-id là cam kết từ nơi bạn muốn sao chép dữ liệu cũ.


-1

nói rằng bạn muốn ở trong chi nhánh A, nhưng với các tệp từ chi nhánh B

tìm tham chiếu cam kết hiện tại của chi nhánh A với git log, ví dụ: "99ce9a2",

git checkout A
git reset --hard B
git reset 99ce9a2

bây giờ bạn sẽ ở trên nhánh A, với cấu trúc thư mục tương ứng với B, hiển thị dưới dạng các thay đổi chưa được phân giai đoạn (Lịch sử không thay đổi).

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.