Kiểm tra xem có cần kéo trong Git không


623

Làm cách nào để kiểm tra xem kho lưu trữ từ xa có thay đổi hay không và tôi cần phải kéo?

Bây giờ tôi sử dụng tập lệnh đơn giản này:

git pull --dry-run | grep -q -v 'Already up-to-date.' && changed=1

Nhưng nó khá nặng.

Có cách nào tốt hơn? Giải pháp lý tưởng sẽ kiểm tra tất cả các nhánh từ xa và trả về tên của các nhánh đã thay đổi và số lần xác nhận mới trong mỗi nhánh.


14
Xin lưu ý: "git pull --dry-run" không hoạt động như mong đợi. Có vẻ như, git pull vượt qua các tùy chọn không xác định trực tiếp để git fetch. Kết quả là kéo git bình thường.

27
"Kéo" chỉ là một cách ngắn để thực hiện "tìm nạp" và "hợp nhất" cùng một lúc, nếu bạn cần kiểm tra trạng thái repo từ xa, bạn thực sự đang mô phỏng "tìm nạp". Vì vậy, git fetch -v --dry-runlà những gì bạn cần.
Claudio Floreani

Câu trả lời:


859

Sử dụng đầu tiên git remote update, để cập nhật từ xa của bạn. Sau đó, bạn có thể thực hiện một trong một số điều, chẳng hạn như:

  1. git status -unosẽ cho bạn biết liệu chi nhánh bạn đang theo dõi đang ở phía trước, phía sau hoặc đã chuyển hướng. Nếu nó không nói gì, thì local và remote đều giống nhau.

  2. git show-branch *mastersẽ hiển thị cho bạn các cam kết trong tất cả các nhánh có tên kết thúc bằng 'master' (ví dụ: masterorigin / master ).

Nếu bạn sử dụng -vvới git remote update( git remote -v update), bạn có thể thấy các nhánh nào đã được cập nhật, vì vậy bạn không thực sự cần thêm bất kỳ lệnh nào.

Tuy nhiên, có vẻ như bạn muốn làm điều này trong một kịch bản hoặc chương trình và kết thúc với một giá trị đúng / sai. Nếu vậy, có nhiều cách để kiểm tra mối quan hệ giữa cam kết CHÍNH hiện tại của bạn và người đứng đầu chi nhánh mà bạn đang theo dõi, mặc dù có bốn kết quả có thể xảy ra, bạn không thể giảm câu trả lời thành có / không. Tuy nhiên, nếu bạn chuẩn bị thực hiện pull --rebasethì bạn có thể coi "cục bộ đứng sau" và "cục bộ đã chuyển hướng" là "cần phải kéo" và hai cái còn lại là "không cần phải kéo".

Bạn có thể lấy id xác nhận của bất kỳ ref nào bằng cách sử dụng git rev-parse <ref>, vì vậy bạn có thể làm điều này cho masterorigin / master và so sánh chúng. Nếu chúng bằng nhau, các nhánh là như nhau. Nếu chúng không bằng nhau, bạn muốn biết cái nào đi trước cái kia. Sử dụng git merge-base master origin/mastersẽ cho bạn biết tổ tiên chung của cả hai nhánh và nếu họ không chuyển hướng thì điều này sẽ giống với cái này hoặc cái kia. Nếu bạn nhận được ba id khác nhau, các nhánh đã chuyển hướng.

Để thực hiện điều này một cách chính xác, ví dụ như trong tập lệnh, bạn cần có thể tham khảo nhánh hiện tại và nhánh từ xa mà nó đang theo dõi. Hàm thiết lập dấu nhắc bash trong /etc/bash_completion.dcó một số mã hữu ích để nhận tên nhánh. Tuy nhiên, có lẽ bạn không thực sự cần phải lấy tên. Git có một số tốc ký gọn gàng để tham khảo các nhánh và cam kết (như được ghi trong tài liệu git rev-parse --help). Cụ thể, bạn có thể sử dụng @cho nhánh hiện tại (giả sử bạn không ở trạng thái tách rời) và @{u}cho nhánh ngược dòng của nó (ví dụ origin/master). Vì vậy, git merge-base @ @{u}sẽ trả về cam kết (băm của) tại đó nhánh hiện tại và phân kỳ ngược dòng của nó git rev-parse @git rev-parse @{u}sẽ cung cấp cho bạn các giá trị băm của hai mẹo. Điều này có thể được tóm tắt trong kịch bản sau đây:

#!/bin/sh

UPSTREAM=${1:-'@{u}'}
LOCAL=$(git rev-parse @)
REMOTE=$(git rev-parse "$UPSTREAM")
BASE=$(git merge-base @ "$UPSTREAM")

if [ $LOCAL = $REMOTE ]; then
    echo "Up-to-date"
elif [ $LOCAL = $BASE ]; then
    echo "Need to pull"
elif [ $REMOTE = $BASE ]; then
    echo "Need to push"
else
    echo "Diverged"
fi

Lưu ý: phiên bản cũ hơn của git không cho phép @riêng, vì vậy bạn có thể phải sử dụng @{0}thay thế.

Dòng này UPSTREAM=${1:-'@{u}'}cho phép bạn tùy ý vượt qua một nhánh ngược dòng một cách rõ ràng, trong trường hợp bạn muốn kiểm tra một nhánh từ xa khác với nhánh được cấu hình cho nhánh hiện tại. Điều này thường sẽ có dạng remotename / Branchname . Nếu không có tham số nào được đưa ra, giá trị mặc định là @{u}.

Kịch bản giả định rằng bạn đã thực hiện một git fetchhoặc git remote updatetrước tiên, để cập nhật các nhánh theo dõi. Tôi đã không xây dựng tập lệnh này thành tập lệnh vì nó linh hoạt hơn để có thể thực hiện tìm nạp và so sánh dưới dạng các thao tác riêng biệt, ví dụ nếu bạn muốn so sánh mà không tìm nạp vì bạn đã tìm nạp gần đây.


4
@takeshin Tôi đoán bạn có thể kết hợp git ls-remote origin -h refs / Heads / master theo đề xuất của @brool với git rev-list --max-Count = 1 origin / master. Nếu chúng trả về cùng một hàm băm, nhánh từ xa đã không thay đổi kể từ lần cuối bạn cập nhật các ref từ xa của bạn (với pull, fetch, cập nhật từ xa, v.v.) Điều này sẽ có lợi thế là bạn sẽ không phải kéo xuống nội dung của tất cả các cam kết ngay lập tức, nhưng có thể để điều đó cho một thời gian thuận tiện hơn. Tuy nhiên, vì cập nhật từ xa là không phá hủy, dù sao bạn cũng có thể làm điều đó.
Neil Mayhew

2
Bạn cũng có thể thử git status -s -u no, cung cấp một đầu ra ngắn hơn git status -u no.
Đám mây Phillip

2
@mhulse git remote -v update,. Nhìn vào đầu ra git remote --helpcho một lời giải thích đầy đủ hơn.
Neil Mayhew

1
@ChrisMaes Điểm tốt. Cú pháp rõ ràng hơn là cần thiết với các phiên bản cũ hơn của git. Tôi đã thử nghiệm với các hệ thống khác nhau mà tôi có và thấy rằng nó @{u}hoạt động với git 1.8.3.2 nhưng @không được. Tuy nhiên @làm việc với 1.8.5.4. Đạo đức của câu chuyện: git tiếp tục cải thiện và đáng để có phiên bản mới nhất bạn có thể.
Neil Mayhew

1
Một specifier hiện được yêu cầu cho @. Bạn có thể sử dụng @ {0} thay vì @.
Ben Davis

132

Nếu bạn có một chi nhánh thượng nguồn

git fetch <remote>
git status

Nếu bạn không có chi nhánh thượng nguồn

So sánh hai nhánh:

git fetch <remote>
git log <local_branch_name>..<remote_branch_name> --oneline

Ví dụ:

git fetch origin

# See if there are any incoming changes
git log HEAD..origin/master --oneline

(Tôi giả sử origin/masterlà chi nhánh theo dõi từ xa của bạn)

Nếu bất kỳ cam kết nào được liệt kê trong đầu ra ở trên, thì bạn có các thay đổi đến - bạn cần hợp nhất. Nếu không có cam kết nào được liệt kê trước git logthì không có gì để hợp nhất.

Lưu ý rằng điều này sẽ hoạt động ngay cả khi bạn ở trong một nhánh tính năng - không có điều khiển từ xa, vì nếu nói rõ ràng origin/masterthay vì sử dụng nhánh ngược dòng được Git ghi nhớ.


2
Thậm chí một ký hiệu ngắn hơn git fetch; git log HEAD.. --onelinecó thể được sử dụng nếu có một nhánh từ xa mặc định cho cục bộ.
phil pirozhkov

@philpirozhkov Nếu bạn có một nhánh từ xa mặc định, tôi nghĩ "trạng thái git" đơn giản. Câu trả lời của tôi là một chung cho bất kỳ hai chi nhánh, trong đó một chi nhánh có thể hoặc không thể theo dõi các chi nhánh khác.
Bệnh dịch hạch

55
git rev-list HEAD...origin/master --countsẽ cung cấp cho bạn tổng số lần cam kết "khác nhau" giữa hai lần.
Jake Berger

1
ngắn gọn và đơn giản Giải pháp yêu thích của tôi chỉ hiển thị các cam kết mới (bật ngón tay cái hai lần)
spankmaster79 18/03/14

Làm cách nào tôi có thể sử dụng tệp này trong tệp bó (Ubuntu) để tôi có thể chạy các lệnh khác chỉ trong trường hợp lệnh này cho thấy cần phải kéo?
Ulysses Alves

69

Nếu đây là cho một kịch bản, bạn có thể sử dụng:

git fetch
$(git rev-parse HEAD) == $(git rev-parse @{u})

(Lưu ý: lợi ích của câu trả lời này so với câu trả lời trước đó là bạn không cần một lệnh riêng để có được tên chi nhánh hiện tại. "git rev-parse --help" để biết thêm chi tiết.)


Tôi đã phát hiện ra @ {u} một cách độc lập và đã cập nhật câu trả lời của mình trước khi tôi thấy câu trả lời của bạn.
Neil Mayhew

1
git rev-parse @{u}Thực sự sẽ hiển thị các cam kết mới nhất mà không có một git fetch?
Kyle Strand

3
Đây là vé! Mặc dù, logic của bạn đang sử dụng ==có nghĩa là "nếu KHÔNG có thay đổi từ thượng nguồn". Tôi đã từng !=kiểm tra "nếu có thay đổi từ thượng nguồn" cho ứng dụng của mình. Đừng quên git fetchđầu tiên!
ChrisPrime 20/03/2015

1
Tôi đã thêm git fetch, vì thực sự cần thiết phải trả lời câu hỏi ban đầu. @là viết tắt của HEADbtw.
user1338062

Người dùng Windows sẽ cần dấu nháy đơn xung quanh @{u}ví dụgit rev-parse '@{u}'
spuder

36

Lệnh

git ls-remote origin -h refs/heads/master

sẽ liệt kê đầu hiện tại trên điều khiển từ xa - bạn có thể so sánh nó với giá trị trước đó hoặc xem bạn có SHA trong repo cục bộ không.


1
Bất kỳ kịch bản mẫu để so sánh các giá trị này?
takeshin

18
git rev-list HEAD...origin/master --countsẽ cung cấp cho bạn tổng số lần cam kết "khác nhau" giữa hai lần.
Jake Berger

3
@jberger để làm rõ, điều đó sẽ chỉ hiển thị số lượng cam kết bạn đứng sau (không phải trước và sau) và nó chỉ hoạt động nếu bạn git fetchhoặc git remote updatetrước. git statuscũng cho thấy một số lượng, btw.
Dennis

1
@Dennis Tôi nghĩ ..là "cam kết về nguồn gốc / chủ, trừ ĐẦU" (tức là số lần xác nhận phía sau). Trong khi đó, ...sự khác biệt đối xứng (tức là phía trước và phía sau)
Jake Berger

3
Thông minh. Theo như tôi có thể nói, đây là giải pháp duy nhất thực sự kiểm tra nguồn gốc của các bản cập nhật nhưng không hoàn toàn làm a fetch.
Kyle Strand

35

Đây là một lớp lót Bash so sánh hàm băm cam kết của nhánh hiện tại với nhánh ngược dòng từ xa của nó, không yêu cầu hoạt động nặng git fetchhoặc git pull --dry-runhoạt động:

[ $(git rev-parse HEAD) = $(git ls-remote $(git rev-parse --abbrev-ref @{u} | \
sed 's/\// /g') | cut -f1) ] && echo up to date || echo not up to date

Đây là cách dòng hơi dày đặc này bị phá vỡ:

  • Các lệnh được nhóm và lồng nhau bằng cú pháp thay thế lệnh$(x) Bash .
  • git rev-parse --abbrev-ref @{u}trả về một ref được viết tắt ngược dòng (ví dụ origin/master), sau đó được chuyển đổi thành các trường được phân tách bằng dấu cách bằng sedlệnh piped , vd origin master.
  • Chuỗi này được đưa vào git ls-remoteđể trả về cam kết đầu của nhánh từ xa. Lệnh này sẽ giao tiếp với kho lưu trữ từ xa. Lệnh piped cutchỉ trích xuất trường đầu tiên (hàm băm cam kết), loại bỏ chuỗi tham chiếu được phân tách bằng tab.
  • git rev-parse HEAD trả về hàm băm cam kết cục bộ.
  • Cú pháp Bash [ a = b ] && x || yhoàn thành một lớp lót: đây là so sánh chuỗi Bash =trong một cấu trúc thử nghiệm [ test ], theo sau là các cấu trúc and-list và hoặc list && true || false.

2
Tôi sẽ không sử dụng / g trên sed nếu bạn sử dụng dấu gạch chéo trong tên nhánh. Đó chỉ là "sed 's / \ // /".
Martyn Davis

@wjordan Giải pháp của bạn không thành công khi kho lưu trữ từ xa không thể truy cập (hoặc đang bảo trì) và sẽ kích hoạt "cập nhật"
khung

20

Tôi đề nghị bạn nên xem kịch bản https://github.com/badele/gitcheck . Tôi đã mã hóa tập lệnh này để kiểm tra một lần vượt qua tất cả các kho Git của bạn và nó cho thấy ai chưa cam kết và ai chưa đẩy / kéo.

Đây là một kết quả mẫu:

Nhập mô tả hình ảnh ở đây


6
gọn gàng, suy nghĩ về việc viết lại nó trong vỏ tinh khiết
Olivier Refalo

1
Bây giờ, bạn cũng có thể sử dụng gitcheck trực tiếp từ một container docker (với các tệp của bạn trong máy chủ của bạn) Để biết thêm thông tin, hãy xem dự án gitchub github
Bruno Adelé

Một công cụ tương tự trong bash git-multi-repo-tooling . git mrepo -cđiều này sẽ hiển thị tất cả các cam kết đang chờ xử lý.
Greg

11

Tôi dựa trên giải pháp này dựa trên ý kiến ​​của @jberger.

if git checkout master &&
    git fetch origin master &&
    [ `git rev-list HEAD...origin/master --count` != 0 ] &&
    git merge origin/master
then
    echo 'Updated!'
else
    echo 'Not updated.'
fi

đề cập đến bình luận trước đó của bạn , tại thời điểm này tôi không thể đưa ra câu trả lời chắc chắn cho bạn. Vào thời điểm tôi đưa ra những bình luận đó, tôi đã lặn xuống vực sâu của git và đặc biệt là từ xa và khác biệt. Đã một vài tháng kể từ đó và rất nhiều kiến ​​thức đó bị chôn vùi trong não tôi. ;) Nếu bạn đang tìm kiếm số lượng cam kết 'khác nhau' giữa hai bên, thì ...dường như đó là một phần hợp lệ trong giải pháp của bạn.
Jake Berger

1
Cảm ơn. Điều này là sạch sẽ.
Shobhit Puri

10

Có rất nhiều tính năng rất phong phú và câu trả lời khéo léo đã. Để cung cấp một số tương phản, tôi có thể thực hiện với một dòng rất đơn giản.

# Check return value to see if there are incoming updates.
if ! git diff --quiet remotes/origin/HEAD; then
 # pull or whatever you want to do
fi

2
Câu trả lời ban đầu còn thiếu '!' trong nếu. Giá trị trả về từ git diff bằng 0, khi không có thay đổi.
thuovila 3/03/2016

Giải pháp tốt nhất của IMO ngoài kia, tôi cần thay thế "từ xa / nguồn gốc / ĐẦU" bằng "nguồn gốc / chủ" hoặc sửa đổi khác
Matthias Michael Engh

9

Tôi nghĩ rằng cách tốt nhất để làm điều này sẽ là:

git diff remotes/origin/HEAD

Giả sử rằng bạn đã đăng ký refspec này. Bạn nên nếu bạn đã nhân bản kho lưu trữ, nếu không (nghĩa là, nếu repo được tạo de novo cục bộ và được đẩy vào điều khiển từ xa), bạn cần thêm refspec một cách rõ ràng.


9

Kịch bản dưới đây hoạt động hoàn hảo.

changed=0
git remote update && git status -uno | grep -q 'Your branch is behind' && changed=1
if [ $changed = 1 ]; then
    git pull
    echo "Updated successfully";
else
    echo "Up-to-date"
fi

6

Tôi sẽ làm theo cách được đề xuất bởi brool. Tập lệnh một dòng sau đây lấy SHA1 của phiên bản được cam kết cuối cùng của bạn và so sánh nó với một trong những nguồn gốc từ xa và chỉ thay đổi nếu chúng khác nhau. Và nó thậm chí còn nhẹ hơn các giải pháp dựa trên git pullhoặc git fetch.

[ `git log --pretty=%H ...refs/heads/master^` != `git ls-remote origin
-h refs/heads/master |cut -f1` ] && git pull

Lệnh này không thành công, nếu kho git được sao chép với "--depth 1" (để giới hạn kích thước tải xuống). Bạn có biết, nếu có một cách để khắc phục nó?
Adam Ryczkowski

Nhật ký git này đang trả về nhiều dòng và báo lỗi "bash: [: quá nhiều đối số" Tôi sẽ chuyển sanggit rev-parse --verify HEAD
Drew Pierce

1
Đây là một so sánh chuỗi đơn giản được thực hiện bởi bash. Nếu có lỗi, tôi sẽ đề nghị bạn kiểm tra cú pháp của bạn (tức là bạn đang gõ sai). Lần chạy đầu tiên git log --pretty=%H ...refs/heads/master^ để lấy SHA1 của phiên bản được cam kết cuối cùng của bạn, sau đó chạy git ls-remote origin -h refs/heads/master |cut -f1 để lấy SHA1 của nguồn gốc từ xa. Hai cái này là lệnh git và không liên quan gì đến bash. Bash làm gì trong dấu ngoặc vuông là so sánh đầu ra từ lệnh đầu tiên với lệnh thứ hai và nếu chúng bằng nhau, nó trả về true và chạy git pull.
Claudio Floreani

"Và nếu chúng bằng nhau, nó trả về true và chạy git pull". Tôi biết tôi thật đáng ghét, nhưng chỉ để cứu ai đó nhầm lẫn, đó phải là "và nếu họ không bằng nhau". Ngoài ra, vì lý do nào, lệnh git đầu tiên không hoạt động đối với tôi. (Tôi đang sử dụng git 2.4.1.) Vì vậy, tôi chỉ sử dụng git log --pretty=%H master | head -n1thay thế. Nhưng tôi không chắc đó có giống hệt nhau không.
xd1le

6

Nếu bạn chạy tập lệnh này, nó sẽ kiểm tra xem nhánh hiện tại có cần git pull:

#!/bin/bash

git fetch -v --dry-run 2>&1 |
    grep -qE "\[up\s+to\s+date\]\s+$(
        git branch 2>/dev/null |
           sed -n '/^\*/s/^\* //p' |
                sed -r 's:(\+|\*|\$):\\\1:g'
    )\s+" || {
        echo >&2 "Current branch need a 'git pull' before commit"
        exit 1
}

Thật tiện lợi khi đặt nó dưới dạng một cam kết Git hook để tránh

Merge branch 'foobar' of url:/path/to/git/foobar into foobar

khi bạn committrước pulling.

Để sử dụng mã này như một cái móc, chỉ cần sao chép / dán tập lệnh vào

.git/hooks/pre-commit

chmod +x .git/hooks/pre-commit

6

Tôi chỉ muốn đăng bài này như một bài viết thực tế vì rất dễ bỏ lỡ điều này trong các bình luận.

Câu trả lời đúng và tốt nhất cho câu hỏi này được đưa ra bởi @Jake Berger, Cảm ơn bạn rất nhiều anh chàng, mọi người đều cần điều này và mọi người đều bỏ lỡ điều này trong các bình luận. Vì vậy, đối với tất cả mọi người đấu tranh với điều này ở đây là câu trả lời chính xác, chỉ cần sử dụng đầu ra của lệnh này để biết nếu bạn cần phải thực hiện một git pull. nếu đầu ra là 0 thì rõ ràng không có gì để cập nhật.

@stackoverflow, cho anh chàng này một tiếng chuông. Cảm ơn @ Jake Berger

git rev-list HEAD...origin/master --count will give you the total number of "different" commits between the two.  Jake Berger Feb 5 '13 at 19:23

4

Chạy git fetch (remote)để cập nhật các ref từ xa của bạn, nó sẽ cho bạn thấy những gì mới. Sau đó, khi bạn kiểm tra chi nhánh địa phương của mình, nó sẽ cho bạn biết liệu nó có ở phía sau không.


Tôi nghĩ rằng anh ấy đã kiểm tra chi nhánh địa phương, vì vậy anh ấy cần một cái gì đó khác để xem liệu nó có ở phía sau không. Anh ấy có thể làm điều này với trạng thái git.
Neil Mayhew

Đúng, sau khi bạn đã tải từ xa, git statuscũng sẽ cho thấy điều đó.
che

1
Đó là một cái gì đó trong tâm trạng git pull --dry-run, nhưng tôi nghĩ rằng nó nặng nề cho một kịch bản cron chạy mỗi phút.
takeshin

@takeshin: Bạn không thể kiểm tra kho lưu trữ từ xa mà không cần truy cập mạng. Nếu không có gì mới fetchthì sẽ không làm gì ngoài việc kiểm tra trạng thái. Nếu bạn cần một phản ứng rất nhanh và nhẹ trên các bản cập nhật từ xa, bạn có thể muốn xem xét việc móc một số loại thông báo vào kho lưu trữ từ xa.
che

@takeshin: nếu bạn muốn kiểm tra repo từ xa mỗi phút tôi nghĩ bạn đã bỏ lỡ điểm DVCS. Toàn bộ ý tưởng là có thể phát triển độc lập trong một thời gian, và sau đó kết hợp tất cả lại với nhau một cách suôn sẻ sau đó. Nó không giống như cvs, svn, p4, v.v. nơi bạn luôn phải làm việc trên bất kỳ thứ gì mới nhất trong kho lưu trữ. Nếu bạn thực sự cần một cái gì đó mà người khác đang làm việc, thì bạn nên sử dụng một cơ chế giao tiếp khác, chẳng hạn như email, để cho bạn biết khi nào nó sẵn sàng để sử dụng.
Neil Mayhew

4

Tất cả các loại đường phức tạp như vậy trong khi giải pháp rất ngắn gọn và dễ dàng:

#!/bin/bash

BRANCH="<your branch name>"
LAST_UPDATE=`git show --no-notes --format=format:"%H" $BRANCH | head -n 1`
LAST_COMMIT=`git show --no-notes --format=format:"%H" origin/$BRANCH | head -n 1`

git remote update
if [ $LAST_COMMIT != $LAST_UPDATE ]; then
        echo "Updating your branch $BRANCH"
        git pull --no-edit
else
        echo "No updates available"
fi

LAST_COMMIT và LAST_UPDATE luôn bằng nhau ngay cả khi có thay đổi
canbax

Giải pháp này rất tốt và đơn giản, cần phải git remote updatethực hiện trước mã của bạn, để có được thông tin cam kết nguồn gốc mới nhất
ak93

Không nên git remote updatenối trước git showcác lệnh?
Setop

2

Đây là phiên bản tập lệnh Bash của tôi để kiểm tra tất cả các kho lưu trữ trong một thư mục được xác định trước:

https://gist.github.com/henryiii/5841984

Nó có thể phân biệt giữa các tình huống phổ biến, như cần kéo và đẩy cần thiết, và nó là đa luồng, do đó việc tìm nạp xảy ra cùng một lúc. Nó có một số lệnh, như kéo và trạng thái.

Đặt một liên kết tượng trưng (hoặc tập lệnh) vào một thư mục trong đường dẫn của bạn, sau đó nó hoạt động như git all status(, v.v.). Nó chỉ hỗ trợ nguồn gốc / master, nhưng nó có thể được chỉnh sửa hoặc kết hợp với một phương thức khác.


1
git ls-remote | cut -f1 | git cat-file --batch-check >&-

sẽ liệt kê mọi thứ được tham chiếu trong bất kỳ điều khiển từ xa nào không có trong repo của bạn. Để nắm bắt các thay đổi từ xa đối với những thứ bạn đã có (ví dụ: đặt lại các cam kết trước đó) cần thêm một chút:

git pack-refs --all
mine=`mktemp`
sed '/^#/d;/^^/{G;s/.\(.*\)\n.* \(.*\)/\1 \2^{}/;};h' .git/packed-refs | sort -k2 >$mine
for r in `git remote`; do 
    echo Checking $r ...
    git ls-remote $r | sort -k2 | diff -b - $mine | grep ^\<
done

1

Có lẽ điều này, nếu bạn muốn thêm tác vụ như crontab:

#!/bin/bash
dir="/path/to/root"
lock=/tmp/update.lock
msglog="/var/log/update.log"

log()
{
        echo "$(date) ${1:-missing}" >> $msglog
}

if [ -f $lock ]; then
        log "Already run, exiting..."
else
        > $lock
        git -C ~/$dir remote update &> /dev/null
        checkgit=`git -C ~/$dir status`
        if [[ ! "$checkgit" =~ "Your branch is up-to-date" ]]; then
                log "-------------- Update ---------------"
                git -C ~/$dir pull &>> $msglog
                log "-------------------------------------"
        fi
        rm $lock

fi
exit 0

1

Sử dụng regrec đơn giản:

str=$(git status) 
if [[ $str =~ .*Your\ branch\ is\ behind.*by.*commits,\ and\ can\ be\ fast-forwarded ]]; then
    echo `date "+%Y-%m-%d %H:%M:%S"` "Needs pull"
else
    echo "Code is up to date"
fi

Điều này sẽ không hoạt động. trạng thái git chỉ là một kiểm tra cục bộ, và vì vậy nó sẽ chỉ cho bạn biết nếu chi nhánh của bạn đứng sau nếu bạn đã cập nhật các defs từ xa của bạn.
minhaz1 16/03/18

0

Tôi sử dụng một phiên bản của một kịch bản dựa trên câu trả lời của Stephen Haberman:

if [ -n "$1" ]; then
    gitbin="git -C $1"
else
    gitbin="git"
fi

# Fetches from all the remotes, although --all can be replaced with origin
$gitbin fetch --all
if [ $($gitbin rev-parse HEAD) != $($gitbin rev-parse @{u}) ]; then
    $gitbin rebase @{u} --preserve-merges
fi

Giả sử tập lệnh này được gọi git-fetch-and-rebase, nó có thể được gọi với một đối số tùy chọndirectory name của kho Git cục bộ để thực hiện thao tác trên. Nếu tập lệnh được gọi mà không có đối số, nó giả sử thư mục hiện tại là một phần của kho Git.

Ví dụ:

# Operates on /abc/def/my-git-repo-dir
git-fetch-and-rebase /abc/def/my-git-repo-dir

# Operates on the Git repository which the current working directory is part of
git-fetch-and-rebase

Nó có sẵn ở đây là tốt.


0

Sau khi đọc nhiều câu trả lời và nhiều bài đăng, và dành nửa ngày để thử nhiều hoán vị khác nhau, đây là những gì tôi đã đưa ra.

Nếu bạn đang ở trên Windows, bạn có thể chạy tập lệnh này trong Windows bằng Git Bash do Git cung cấp cho Windows (cài đặt hoặc di động).

Kịch bản này yêu cầu đối số

- đường dẫn cục bộ, vd / d / source / project1
- URL Git, ví dụ https: //username@bitbucket.org/username/project1.git
- mật khẩu

nếu không nên nhập mật khẩu trên dòng lệnh bằng văn bản thuần túy,
sau đó sửa đổi tập lệnh để kiểm tra xem GITPASS có trống không; đừng
thay thế và để Git nhắc nhập mật khẩu

Kịch bản sẽ

- Find the current branch
- Get the SHA1 of the remote on that branch
- Get the SHA1 of the local on that branch
- Compare them.

Nếu có một thay đổi như được in bởi tập lệnh, thì bạn có thể tiến hành tìm nạp hoặc kéo. Kịch bản có thể không hiệu quả, nhưng nó hoàn thành công việc cho tôi.

Cập nhật - 2015-10-30: stderr thành dev null để ngăn in URL bằng mật khẩu lên bàn điều khiển.

#!/bin/bash

# Shell script to check if a Git pull is required.

LOCALPATH=$1
GITURL=$2
GITPASS=$3

cd $LOCALPATH
BRANCH="$(git rev-parse --abbrev-ref HEAD)"

echo
echo git url = $GITURL
echo branch = $BRANCH

# Bash replace - replace @ with :password@ in the GIT URL
GITURL2="${GITURL/@/:$GITPASS@}"
FOO="$(git ls-remote $GITURL2 -h $BRANCH 2> /dev/null)"
if [ "$?" != "0" ]; then
  echo cannot get remote status
  exit 2
fi
FOO_ARRAY=($FOO)
BAR=${FOO_ARRAY[0]}
echo [$BAR]

LOCALBAR="$(git rev-parse HEAD)"
echo [$LOCALBAR]
echo

if [ "$BAR" == "$LOCALBAR" ]; then
  #read -t10 -n1 -r -p 'Press any key in the next ten seconds...' key
  echo No changes
  exit 0
else
  #read -t10 -n1 -r -p 'Press any key in the next ten seconds...' key
  #echo pressed $key
  echo There are changes between local and remote repositories.
  exit 1
fi

0

Đối với những người dùng windows cuối cùng trả lời câu hỏi này, tôi đã sửa đổi một số câu trả lời thành tập lệnh powershell. Tinh chỉnh khi cần thiết, lưu vào một .ps1tệp và chạy theo yêu cầu hoặc lên lịch nếu bạn muốn.

cd C:\<path to repo>
git remote update                           #update remote
$msg = git remote show origin               #capture status
$update = $msg -like '*local out of date*'
if($update.length -gt 0){                   #if local needs update
    Write-Host ('needs update')
    git pull
    git reset --hard origin/master
    Write-Host ('local updated')
} else {
    Write-Host ('no update needed')
}

0

Bởi vì câu trả lời của Neils đã giúp tôi rất nhiều ở đây là bản dịch Python không có phụ thuộc:

import os
import logging
import subprocess

def check_for_updates(directory:str) -> None:
    """Check git repo state in respect to remote"""
    git_cmd = lambda cmd: subprocess.run(
        ["git"] + cmd,
        cwd=directory,
        stdout=subprocess.PIPE,
        check=True,
        universal_newlines=True).stdout.rstrip("\n")

    origin = git_cmd(["config", "--get", "remote.origin.url"])
    logging.debug("Git repo origin: %r", origin)
    for line in git_cmd(["fetch"]):
        logging.debug(line)
    local_sha = git_cmd(["rev-parse", "@"])
    remote_sha = git_cmd(["rev-parse", "@{u}"])
    base_sha = git_cmd(["merge-base", "@", "@{u}"])
    if local_sha == remote_sha:
        logging.info("Repo is up to date")
    elif local_sha == base_sha:
        logging.info("You need to pull")
    elif remote_sha == base_sha:
        logging.info("You need to push")
    else:
        logging.info("Diverged")

check_for_updates(os.path.dirname(__file__))

thứ


-5

Bạn cũng có thể tìm thấy một kịch bản Phing , người thực hiện điều đó ngay bây giờ.

Tôi cần một giải pháp để tự động cập nhật môi trường sản xuất của mình và chúng tôi rất vui nhờ tập lệnh này mà tôi đang chia sẻ.

Kịch bản được viết bằng XML và cần Phing .


Có lẽ không nên sao chép dán tập lệnh ở đây, tôi vẫn đang cập nhật nó ...
Pol Dellaiera
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.