Git
Câu trả lời này bao gồm GitHub vì nhiều người cũng đã hỏi về điều đó.
Kho lưu trữ cục bộ
Git (cục bộ) có một thư mục ( .git
) mà bạn cam kết các tệp của mình và đây là 'kho lưu trữ cục bộ' của bạn. Điều này khác với các hệ thống như SVN nơi bạn thêm và cam kết vào kho lưu trữ từ xa ngay lập tức.
Git lưu trữ từng phiên bản của một tệp thay đổi bằng cách lưu toàn bộ tệp. Nó cũng khác với SVN về mặt này vì bạn có thể đi đến bất kỳ phiên bản riêng lẻ nào mà không cần 'tái tạo' nó thông qua các thay đổi delta.
Git hoàn toàn không 'khóa' các tệp và do đó tránh được chức năng 'khóa độc quyền' để chỉnh sửa (các hệ thống cũ hơn như pvcs xuất hiện), vì vậy tất cả các tệp luôn có thể được chỉnh sửa, ngay cả khi ngoại tuyến. Nó thực sự làm một công việc tuyệt vời là hợp nhất các thay đổi tệp (trong cùng một tệp!) Trong quá trình kéo hoặc tìm nạp / đẩy đến một kho lưu trữ từ xa như GitHub. Lần duy nhất bạn cần thực hiện các thay đổi thủ công (thực sự chỉnh sửa một tệp) là nếu hai thay đổi liên quan đến cùng một dòng mã.
Chi nhánh
Các nhánh cho phép bạn giữ mã chính (nhánh 'chính'), tạo một bản sao (một nhánh mới) và sau đó làm việc trong nhánh mới đó. Nếu công việc mất một thời gian hoặc chủ nhân nhận được rất nhiều cập nhật kể từ khi chi nhánh được thực hiện thì việc hợp nhất hoặc nổi loạn (thường được ưu tiên cho lịch sử tốt hơn và dễ dàng giải quyết xung đột hơn) đối với chi nhánh chính nên được thực hiện. Khi bạn hoàn thành, bạn hợp nhất các thay đổi được thực hiện trong nhánh trở lại vào kho lưu trữ chính. Nhiều tổ chức sử dụng các nhánh cho từng phần công việc cho dù đó là một tính năng, lỗi hoặc mục vặt. Các tổ chức khác chỉ sử dụng các chi nhánh cho các thay đổi lớn như nâng cấp phiên bản.
Ngã ba: Với một nhánh bạn kiểm soát và quản lý chi nhánh, trong khi với một ngã ba, người khác điều khiển chấp nhận mã trở lại.
Nói rộng ra, có hai cách tiếp cận chính để làm chi nhánh. Đầu tiên là giữ hầu hết các thay đổi trên nhánh chính, chỉ sử dụng các nhánh cho những thứ lớn hơn và chạy dài hơn như thay đổi phiên bản mà bạn muốn có hai nhánh có sẵn cho các nhu cầu khác nhau. Thứ hai là về cơ bản bạn tạo một nhánh cho mọi yêu cầu tính năng, sửa lỗi hoặc xử lý và sau đó tự quyết định khi nào thực sự hợp nhất các nhánh đó vào nhánh chính. Mặc dù điều này nghe có vẻ tẻ nhạt, nhưng đây là một cách tiếp cận phổ biến và là cách tiếp cận mà tôi hiện đang sử dụng và khuyên dùng vì điều này giữ cho nhánh chính sạch hơn và đó là chủ mà chúng tôi quảng bá để sản xuất, vì vậy chúng tôi chỉ muốn hoàn thành, đã kiểm tra mã, thông qua việc nổi loạn và sáp nhập các chi nhánh.
Cách tiêu chuẩn để đưa một nhánh 'vào' thành chủ là làm a merge
. Các chi nhánh cũng có thể được "khởi động lại" để 'dọn dẹp' lịch sử. Nó không ảnh hưởng đến trạng thái hiện tại và được thực hiện để đưa ra lịch sử 'sạch hơn'.
Về cơ bản, ý tưởng là bạn phân nhánh từ một điểm nhất định (thường là từ chủ). Vì bạn đã phân nhánh, bản thân 'chủ nhân' đã di chuyển về phía trước từ điểm phân nhánh đó. Sẽ là 'sạch hơn' (dễ giải quyết vấn đề hơn và lịch sử sẽ dễ hiểu hơn) nếu tất cả các thay đổi bạn đã thực hiện trong một nhánh được chơi với trạng thái hiện tại của chủ nhân với tất cả các thay đổi mới nhất của nó. Vì vậy, quá trình là: lưu các thay đổi; lấy chủ nhân 'mới', và sau đó áp dụng lại (đây là phần rebase) các thay đổi một lần nữa chống lại điều đó. Xin lưu ý rằng rebase, giống như hợp nhất, có thể dẫn đến xung đột mà bạn phải giải quyết thủ công (nghĩa là chỉnh sửa và khắc phục).
Một hướng dẫn cần lưu ý:
Chỉ rebase nếu chi nhánh là cục bộ và bạn chưa đẩy nó đến điều khiển từ xa!
Điều này chủ yếu là vì việc nổi loạn có thể làm thay đổi lịch sử mà những người khác nhìn thấy có thể bao gồm các cam kết của chính họ.
Theo dõi chi nhánh
Đây là những nhánh được đặt tên origin/branch_name
(trái ngược với chỉ branch_name
). Khi bạn đang đẩy và kéo mã đến / từ các kho lưu trữ từ xa thì đây thực sự là cơ chế mà qua đó xảy ra. Ví dụ, khi bạn git push
gọi một nhánh building_groups
, nhánh của bạn sẽ đi trước origin/building_groups
và sau đó đến kho lưu trữ từ xa. Tương tự, nếu bạn làm một git fetch building_groups
, tập tin được lấy sẽ được đặt trong origin/building_groups
nhánh của bạn . Sau đó, bạn có thể chọn hợp nhất chi nhánh này vào bản sao cục bộ của mình. Thực tiễn của chúng tôi là luôn luôn thực hiện một git fetch
và hợp nhất thủ công chứ không chỉ là một git pull
(thực hiện cả hai điều trên trong một bước).
Lấy các nhánh mới.
Bắt các nhánh mới: Tại điểm ban đầu của một bản sao, bạn sẽ có tất cả các nhánh. Tuy nhiên, nếu các nhà phát triển khác thêm các nhánh và đẩy chúng vào điều khiển từ xa thì cần phải có một cách để 'biết' về các nhánh đó và tên của chúng để có thể kéo chúng xuống cục bộ. Điều này được thực hiện thông qua git fetch
việc sẽ đưa tất cả các nhánh mới và thay đổi vào kho lưu trữ cục bộ bằng cách sử dụng các nhánh theo dõi (ví dụ origin/
:). Khi fetch
ed, người ta có thể git branch --remote
liệt kê các nhánh theo dõi và git checkout [branch]
thực sự chuyển sang bất kỳ nhánh nào.
Sáp nhập
Sáp nhập là quá trình kết hợp các thay đổi mã từ các nhánh khác nhau hoặc từ các phiên bản khác nhau của cùng một nhánh (ví dụ: khi một nhánh cục bộ và điều khiển từ xa không đồng bộ). Nếu một người đã phát triển công việc trong một chi nhánh và công việc đã hoàn thành, sẵn sàng và được thử nghiệm, thì nó có thể được sáp nhập vào master
chi nhánh. Điều này được thực hiện bằng cách git checkout master
chuyển sang master
chi nhánh, sau đó git merge your_branch
. Việc hợp nhất sẽ mang tất cả các tệp khác nhau và thậm chí các thay đổi khác nhau vào cùng một tệp . Điều này có nghĩa là nó thực sự sẽ thay đổi mã bên trong các tệp để hợp nhất tất cả các thay đổi.
Khi thực hiện checkout
của master
nó cũng khuyến khích để làm một git pull origin master
để có được phiên bản mới nhất của các bậc thầy từ xa sáp nhập vào tổng thể địa phương của bạn. Nếu chủ từ xa thay đổi, tức là moved forward
, bạn sẽ thấy thông tin phản ánh điều đó trong thời gian đó git pull
. Nếu đó là trường hợp (chủ đã thay đổi), bạn nên làm chủ git checkout your_branch
và sau đó rebase
nên làm chủ để các thay đổi của bạn thực sự được 'phát lại' trên đầu trang của chủ 'mới'. Sau đó, bạn sẽ tiếp tục với việc cập nhật tổng thể như được hiển thị trong đoạn tiếp theo.
Nếu không có xung đột, thì master sẽ có các thay đổi mới được thêm vào. Nếu có xung đột, điều này có nghĩa là các tệp tương tự có các thay đổi xung quanh các dòng mã tương tự mà nó không thể tự động hợp nhất. Trong trường hợp git merge new_branch
này sẽ báo cáo rằng có (các) xung đột để giải quyết. Bạn 'giải quyết' chúng bằng cách chỉnh sửa các tệp (sẽ có cả hai thay đổi trong đó), chọn các thay đổi bạn muốn, xóa theo nghĩa đen của các thay đổi bạn không muốn và sau đó lưu tệp. Các thay đổi được đánh dấu bằng các dấu phân cách như ========
và <<<<<<<<
.
Khi bạn đã giải quyết bất kỳ xung đột nào, bạn sẽ một lần nữa git add
và git commit
những thay đổi đó để tiếp tục hợp nhất (bạn sẽ nhận được phản hồi từ git trong quá trình này để hướng dẫn bạn).
Khi quá trình không hoạt động tốt, bạn sẽ thấy git merge --abort
rất thuận tiện để thiết lập lại mọi thứ.
Tương tác nổi loạn và đè bẹp / sắp xếp lại / xóa cam kết
Nếu bạn đã thực hiện công việc theo nhiều bước nhỏ, ví dụ: bạn cam kết mã là 'công việc đang tiến hành' mỗi ngày, bạn có thể muốn 'ép' nhiều cam kết nhỏ đó thành một vài cam kết lớn hơn. Điều này có thể đặc biệt hữu ích khi bạn muốn thực hiện đánh giá mã với các đồng nghiệp. Bạn không muốn phát lại tất cả các 'bước' bạn đã thực hiện (thông qua các cam kết), bạn muốn nói rằng đây là hiệu ứng kết thúc (khác biệt) của tất cả các thay đổi của tôi cho công việc này trong một lần cam kết.
Yếu tố quan trọng để đánh giá khi xem xét liệu có nên làm điều này hay không là nhiều lần xác nhận đối với cùng một tệp hoặc nhiều tệp hơn một lần (tốt hơn để xóa các cam kết trong trường hợp đó). Điều này được thực hiện với công cụ rebasing tương tác. Công cụ này cho phép bạn xóa các xác nhận, xóa các xác nhận, gửi lại tin nhắn, v.v. Ví dụ: git rebase -i HEAD~10
( lưu ý: đó là a ~
, không phải a-
) đưa ra các điều sau:
Hãy cẩn thận và sử dụng công cụ này 'cẩn thận'. Thực hiện một squash / xóa / sắp xếp lại tại một thời điểm, thoát và lưu cam kết đó, sau đó nhập lại công cụ. Nếu các xác nhận không liền kề, bạn có thể sắp xếp lại chúng (và sau đó ép nếu cần). Bạn thực sự có thể xóa các cam kết ở đây, nhưng bạn thực sự cần chắc chắn về những gì bạn đang làm khi bạn làm điều đó!
Nĩa
Có hai cách tiếp cận chính để hợp tác trong kho Git. Đầu tiên, chi tiết ở trên, trực tiếp thông qua các nhánh mà mọi người kéo và đẩy từ / đến. Những cộng tác viên này có các khóa SSH được đăng ký với kho lưu trữ từ xa. Điều này sẽ cho phép họ đẩy trực tiếp đến kho lưu trữ đó. Nhược điểm là bạn phải duy trì danh sách người dùng. Cách tiếp cận khác - forking - cho phép bất kỳ ai 'fork' kho lưu trữ, về cơ bản tạo một bản sao cục bộ trong tài khoản kho lưu trữ Git của riêng họ. Sau đó, họ có thể thực hiện các thay đổi và khi hoàn tất gửi 'yêu cầu kéo' (thực sự đó là một 'cú hích' từ họ và yêu cầu 'kéo' cho người duy trì kho lưu trữ thực tế) để mã được chấp nhận.
Phương pháp thứ hai này, sử dụng dĩa, không yêu cầu ai đó duy trì danh sách người dùng cho kho lưu trữ.
GitHub
GitHub (kho lưu trữ từ xa) là một nguồn từ xa mà bạn thường đẩy và kéo những thay đổi đã cam kết đến nếu bạn có (hoặc được thêm vào) một kho lưu trữ như vậy, vì vậy cục bộ và từ xa thực sự khá khác biệt. Một cách khác để nghĩ về một kho lưu trữ từ xa là nó là một .git
cấu trúc thư mục sống trên một máy chủ từ xa.
Khi bạn 'ngã ba' - trong GitHub GUI trình duyệt web mà bạn có thể nhấp vào nút này - bạn tạo một bản sao ( 'bản sao') của các mã trong của bạn tài khoản GitHub. Lần đầu tiên bạn có thể tinh tế một chút, vì vậy hãy đảm bảo rằng bạn nhìn vào kho lưu trữ mà một cơ sở mã được liệt kê bên dưới - chủ sở hữu ban đầu hoặc 'rẽ nhánh từ' và bạn, ví dụ như thế này:
Khi bạn có bản sao cục bộ, bạn có thể thay đổi theo ý muốn (bằng cách kéo và đẩy chúng vào máy cục bộ). Khi bạn đã hoàn tất, sau đó bạn gửi một 'yêu cầu kéo' cho chủ sở hữu / quản trị kho lưu trữ ban đầu (nghe có vẻ lạ mắt nhưng thực ra bạn chỉ cần nhấp vào đây :) và họ 'kéo' nó vào.
Phổ biến hơn cho một nhóm làm việc về mã cùng nhau là 'sao chép' kho lưu trữ (nhấp vào biểu tượng 'sao chép' trên màn hình chính của kho lưu trữ). Sau đó, gõ địa phương git clone
và dán. Điều này sẽ thiết lập cho bạn cục bộ và bạn cũng có thể đẩy và kéo đến vị trí GitHub (được chia sẻ).
Bản sao
Như đã chỉ ra trong phần trên GitHub, bản sao là bản sao của kho lưu trữ. Khi bạn có một kho lưu trữ từ xa, bạn đưa ra git clone
lệnh chống lại URL của nó và sau đó bạn kết thúc bằng một bản sao cục bộ hoặc bản sao của kho lưu trữ. Bản sao này có tất cả mọi thứ , các tệp, nhánh chính, các nhánh khác, tất cả các cam kết hiện có, toàn bộ shebang. Đây là bản sao mà bạn thực hiện thêm và cam kết và sau đó chính kho lưu trữ từ xa là thứ bạn đẩy những cam kết đó. Chính khái niệm cục bộ / từ xa này đã biến Git (và các hệ thống tương tự như Mercurial) thành DVCS ( Hệ thống kiểm soát phiên bản phân tán ) trái ngược với các CVS truyền thống (Hệ thống phiên bản mã) như SVN, PVCS, CVS, v.v. bạn cam kết trực tiếp đến kho lưu trữ từ xa.
Hình dung
Hình dung của các khái niệm cốt lõi có thể được nhìn thấy tại
http://marklodato.github.com/visual-git-guide/index-en.html và
http://ndpsoftware.com/git-chcoateet.html#loc=index
Nếu bạn muốn hiển thị trực quan về cách các thay đổi đang hoạt động, bạn không thể đánh bại công cụ trực quan gitg
( gitx
dành cho macOS) bằng GUI mà tôi gọi là 'bản đồ tàu điện ngầm' (đặc biệt là Tàu điện ngầm Luân Đôn), tuyệt vời để hiển thị ai đã làm gì, làm thế nào mọi thứ thay đổi, chuyển hướng và sáp nhập, vv
Bạn cũng có thể sử dụng nó để thêm, cam kết và quản lý các thay đổi của mình!
Mặc dù gitg / gitx khá tối thiểu, số lượng công cụ GUI vẫn tiếp tục mở rộng. Nhiều người dùng Mac sử dụng ngã ba gitx của Brotherbard và cho Linux, một tùy chọn tuyệt vời là git thông minh với giao diện trực quan nhưng mạnh mẽ:
Lưu ý rằng ngay cả với một công cụ GUI, bạn có thể sẽ thực hiện rất nhiều lệnh tại dòng lệnh.
Đối với điều này, tôi có các bí danh sau trong ~/.bash_aliases
tệp của mình (được gọi từ ~/.bashrc
tệp của tôi cho mỗi phiên cuối):
# git
alias g='git status'
alias gcob='git checkout -b '
alias gcom='git checkout master'
alias gd='git diff'
alias gf='git fetch'
alias gfrm='git fetch; git reset --hard origin/master'
alias gg='git grep '
alias gits='alias | grep "^alias g.*git.*$"'
alias gl='git log'
alias gl1='git log --oneline'
alias glf='git log --name-status'
alias glp='git log -p'
alias gpull='git pull '
alias gpush='git push '
VÀ tôi có "bí danh git" trong ~/.gitconfig
tệp của mình - tại sao lại có những thứ này?
Vì vậy, việc hoàn thành chi nhánh (với khóa TAB) hoạt động!
Vì vậy, đây là:
[alias]
co = checkout
cob = checkout -b
Sử dụng ví dụ: git co [branch]
<- hoàn thành tab cho các chi nhánh sẽ hoạt động.
Công cụ học tập GUI
Bạn có thể thấy https://learngitbranching.js.org/ hữu ích trong việc tìm hiểu một số khái niệm cơ bản. Ảnh chụp màn hình:
Video: https://youtu.be/23JqqcLPss0
Cuối cùng, 7 phao cứu sinh quan trọng!
Bạn thực hiện thay đổi, thêm và cam kết chúng (nhưng không đẩy) và sau đó oh! bạn nhận ra bạn đang làm chủ
git reset [filename(s)]
git checkout -b [name_for_a_new_branch]
git add [file(s)]
git commit -m "A useful message"
Voila! You've moved that 'master' commit to its own branch !
Bạn làm hỏng một số tệp trong khi làm việc trong một chi nhánh địa phương và chỉ muốn quay lại những gì bạn đã có lần cuối cùng bạn đã làm git pull
:
git reset --hard origin/master # You will need to be comfortable doing this!
Bạn bắt đầu thực hiện các thay đổi cục bộ, bạn chỉnh sửa một nửa tá tệp và sau đó, ôi thôi, bạn vẫn ở trong nhánh chính (hoặc khác):
git checkout -b new_branch_name # just create a new branch
git add . # add the changes files
git commit -m"your message" # and commit them
Bạn làm rối một tệp cụ thể trong nhánh hiện tại của mình và về cơ bản muốn 'đặt lại' tệp đó (mất các thay đổi) về lần cuối cùng bạn lấy nó từ kho lưu trữ từ xa:
git checkout your/directories/filename
Điều này thực sự đặt lại tệp (giống như nhiều lệnh Git, nó không được đặt tên tốt cho những gì nó đang làm ở đây).
Bạn thực hiện một số thay đổi cục bộ, bạn muốn đảm bảo rằng bạn không mất chúng trong khi bạn thực hiện git reset
hoặc rebase
: Tôi thường tạo một bản sao thủ công của toàn bộ dự án ( cp -r ../my_project ~/
) khi tôi không chắc chắn liệu mình có thể gây rối trong Git hay mất quan trọng thay đổi.
Bạn đang nổi loạn nhưng mọi thứ bị rối tung:
git rebase --abort # To abandon interactive rebase and merge issues
Thêm chi nhánh Git của bạn vào PS1
lời nhắc của bạn (xem https://unix.stackexchange.com/a/127800/10043 ), ví dụ:
Chi nhánh là selenium_rspec_conversion
.