Git: Cách di chuyển qua lại giữa các lần cam kết


76

Tôi có một câu hỏi dành cho người mới về Git:

Tôi cần phải di chuyển tới lui trong lịch sử của một chi nhánh. Điều đó có nghĩa là, tôi cần đưa tất cả các tệp về trạng thái của chúng trong một số bản sửa đổi cũ, và sau đó tôi cần quay lại trạng thái mới nhất trong kho lưu trữ. Tôi không cần phải cam kết.

Với SVN, nó sẽ là

svn up -r800

để chuyển đến bản sửa đổi 800 và

svn up

để đồng bộ hóa với kho lưu trữ.

Tôi biết mã băm của cam kết mà tôi muốn lấy lại, vì vậy tôi đã thử

git reset <hash>

mà dường như đưa tôi đến đó. Nhưng sau đó tôi đã cố gắng

git pull

nhưng điều đó phàn nàn về những xung đột.

Vì vậy, cách thích hợp để di chuyển qua lịch sử của chi nhánh là gì?

Tôi đang nghĩ về SVN, vì vậy đừng ngại chỉ cho tôi một số hướng dẫn hay. Lưu ý rằng tôi đã kiểm tra http://git.or.cz/course/svn.htmlhttp://www.youtube.com/watch?v=8dhZ9BXQgc4 .

Cảm ơn, Ondra.


1
Lưu ý phụ: Tôi đã quen với việc tránh git pullhoàn toàn. Thay vào đó, tôi sử dụng git fetch --allbí danh gutrong bash và luôn gitkmở, xem tất cả các nhánh - xem Xem -> chỉnh sửa -> chọn tất cả 4 hộp kiểm. Sau đó, tôi di chuyển bằng cách sử dụng git resethoặc gist stash+ git co, tùy thuộc vào những gì tôi cần.
Ondra Žižka

Câu trả lời:


71

Tôi cũng là một người dùng svn trước đây và bây giờ sử dụng git cho tất cả các dự án của tôi.

Khi sử dụng git, bạn nên thay đổi cách suy nghĩ từ kiến ​​trúc máy khách-máy chủ được sử dụng trong svn. Trong svn, mọi thay đổi đều cần kết nối với máy chủ. Sử dụng git, repo của bạn nằm trong thư mục làm việc. Bạn không cần kết nối cho mọi hành động repo.

Chỉ sử dụng git pushgit pullđể đồng bộ hóa với repo. Hãy nghĩ về nó giống như sử dụng rsync hoặc bất kỳ giải pháp sao lưu nào, để làm cho hai nơi có nội dung giống hệt nhau. Giống như bạn kết nối đĩa cứng sao lưu bên ngoài, sau đó làm cho nội dung trong đó giống với nội dung trong chính của bạn. Đó là cách sử dụng git pullgit push.

Nếu bạn chỉ muốn xem lại lịch sử, hãy làm điều đó bằng cách sử dụng git checkout. Xem id sửa đổi bằng cách sử dụng git history. Nếu bạn đang sử dụng Linux, hãy sử dụng gitkđể xem cây sửa đổi. Trong Windows, git rùa có thể hiển thị nó bằng cách sử dụng đồ thị sửa đổi.

Để quay lại phiên bản mới nhất, hãy sử dụng git checkout master. Trước khi thực hiện bất kỳ lệnh nào, hãy luôn bắt mình làm git status. Lệnh này sẽ hiển thị bất cứ điều gì bạn cần biết về tình trạng repo hiện tại và hành động bạn cần làm để làm cho nó đúng. Trước khi thực hiện git pullgit push, tốt hơn hết bạn nên đảm bảo rằng git statuskết quả chứa văn bản working directory clean.

Nếu bạn cần hoàn nguyên một tệp về bản sửa đổi trước đó, bạn có thể làm điều đó với git merge. Trước khi thực hiện nó với một tệp, hãy kiểm tra nó trước với git diff. Ví dụ: git diff rev1:rev2 filename. Nó sẽ in ra bất kỳ sự khác biệt nào giữa hai bản sửa đổi. Thay đổi trong rev1 sẽ được thay thế bằng những thay đổi trong rev2. Vì vậy, để hoàn nguyên, rev2 sẽ cũ hơn rev1. Sau khi bạn hài lòng với kết quả khác, hãy làm điều đó với git merge, chỉ cần thay thế diffbằng merge, tất cả các tham số khác giữ nguyên.

Tôi hy vọng cái này sẽ giúp bạn. Chìa khóa chính là thấy rằng dir đang hoạt động của bạn là repo của bạn. Hiểu được điều này sẽ giúp bạn sử dụng git với đầy đủ khả năng của nó. Chúc may mắn.


39

Bạn có thể sử dụng git checkoutđể kiểm tra bất kỳ cam kết nào và sau đó sử dụng nó với tên chi nhánh để quay lại chi nhánh đã đặt tên.

git checkoutvới id cam kết chứ không phải tên nhánh sẽ di chuyển bạn khỏi bất kỳ nhánh nào đã đặt tên và chuyển sang cái được gọi là phần đầu tách rời .

Nếu bạn sử dụng git resetthì nó sẽ tự di chuyển chi nhánh của bạn trở lại trạng thái cũ, loại bỏ các cam kết gần đây hơn mà có thể không phải là điều bạn muốn.


Cái gì checkout thực sự làm? Nó có thay đổi các tệp thành trạng thái của cam kết đã cho, bằng cách áp dụng ngược lại các bản vá của các cam kết giữa trạng thái hiện tại và trạng thái của cam kết đã cho không?
Ondra Žižka

Tôi đã tìm thấy git resetgit reset origin. Tôi sẽ không thực hiện bất kỳ cam kết nào, vì vậy không quan trọng liệu tôi có bỏ các cam kết gần đây hay không khi nó có thể khôi phục dễ dàng (có nghĩa là chỉ bằng một lệnh).
Ondra Žižka

1
git checkout không thực hiện thay đổi vĩnh viễn. Để làm điều đó, hãy sử dụng git merge. Xem câu trả lời của tôi.
Donny Kurnia

1
checkout reset là vùng chỉ mục / bộ nhớ cache / dàn vào cây được chỉ định bởi cam kết nhất định và sau đó cập nhật cây làm việc để khớp với bộ nhớ cache. Nó không cần phải áp dụng lại bản vá; nó chỉ sử dụng cây như ở cam kết đã cho. (Nó cũng có lỗi kiểm tra và cập nhật nhánh đã kiểm tra nếu bạn chuyển cho nó một tên nhánh.)
CB Bailey

30

Các câu trả lời khác là thông tin, nhưng tôi tin rằng điều này gần nhất với những gì OP muốn:

Thêm hai hàm này vào ~ / .bashrc của bạn:

# checkout prev (older) revision
git_prev() {
    git checkout HEAD~
}

# checkout next (newer) commit
git_next() {
    BRANCH=`git show-ref | grep $(git show-ref -s -- HEAD) | sed 's|.*/\(.*\)|\1|' | grep -v HEAD | sort | uniq`
    HASH=`git rev-parse $BRANCH`
    PREV=`git rev-list --topo-order HEAD..$HASH | tail -1`
    git checkout $PREV
}

Sử dụng:

$ git_prev
Previous HEAD position was 7042c8a... Commit message2
HEAD is now at d753ecc... Commit message1

$ git_next
Previous HEAD position was d753ecc... Commit message1
HEAD is now at 7042c8a... Commit message2

Lưu ý : Các lệnh này luôn nhập trạng thái HEAD tách rời . Nếu bạn git_prevthìgit_next từ một chi nhánh hiện đã đăng xuất, bạn sẽ quay lại ở phiên bản mới nhất nhưng bạn sẽ ở trạng thái HEAD tách rời. Làm git checkout BRANCH_NAMEđể trở lại bình thường.


Khi bạn đang làm những việc như vậy, hãy xem qua các bí danh git có thể rất đáng giá.
cai nghiện

Tôi yêu câu trả lời này và nó đã làm việc trong một phút nhưng bây giờ khi tôi chạy git_next tôi có được điều nàyusage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]] [-e pattern] [-f file] [--binary-files=value] [--color=when] [--context[=num]] [--directories=action] [--label] [--line-buffered] [--null] [pattern] [file ...]
Squirrl

11

Hãy thử git reflog, điều này liệt kê các cam kết và kiểm tra bạn đã thực hiện để chuyển đổi giữa các cam kết, thậm chí cả các cam kết bạn đã mất khi thanh toán sang cam kết trước đó.

Sau đó, bạn có thể thử git checkout <hash of a commit>chuyển sang cam kết đó.

Hi vọng điêu nay co ich!


7

Để kiểm tra một phiên bản khác của tệp, hãy sử dụng

git checkout rev -- filename

Trong đó rev có thể là ID của cam kết, tên của nhánh, tên của thẻ hoặc phiên bản tương đối.

Sử dụng git log,gitk để xem xét các phiên bản để xem bạn muốn phiên bản nào của tệp.

Để đặt phiên bản này của tệp vĩnh viễn, bạn cần cam kết tệp: git add filename; git commit filename

Tôi không khuyên bạn nên git pullkiểm tra các phiên bản vì nó thực hiện hợp nhất - có khả năng sửa đổi trạng thái hiện tại của bạn.

Bạn không cần phải sử dụng git resettrong trường hợp này, trừ khi bạn git addlà một tệp bạn quyết định không cam kết.


ngọt ngào jeebus hãy cẩn thận khi làm điều này. Đồng nghiệp của tôi đã thực hiện lệnh này để thử các thay đổi từ chi nhánh của tôi, xóa sạch khoảng một tuần công việc của tôi và đẩy nó lên repo bằng cách thực hiện điều này ...
karina

Miễn là đồng nghiệp của bạn không thực hiện push -f, bạn luôn có thể hoàn nguyên cam kết của anh ấy và khôi phục công việc còn thiếu. Nếu bạn có quyền truy cập vào repo mà anh ấy đã đẩy đến, bạn có thể khôi phục ngay cả một lực đẩy thông qua git reflog. Ngoài ra, nếu bạn vẫn còn nhánh của mình, nó có thể khôi phục được. Nhưng có, bạn phải cẩn thận.
Jamey Hicks
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.