Bí danh Git với các tham số vị trí


261

Về cơ bản tôi đang cố gắng bí danh:

git files 9fa3

... để thực thi lệnh:

git diff --name-status 9fa3^ 9fa3

nhưng git không xuất hiện để truyền tham số vị trí cho lệnh bí danh. Tôi đã thử:

[alias]
    files = "!git diff --name-status $1^ $1"
    files = "!git diff --name-status {1}^ {1}"

... Và một vài người khác nhưng những người đó đã không làm việc.

Trường hợp thoái hóa sẽ là:

$ git echo_reverse_these_params a b c d e
e d c b a

... Làm thế nào tôi có thể làm cho công việc này?


17
Lưu ý rằng trong git 1.8.2.1, có thể thực hiện điều đó mà không cần hàm shell (cách tiếp cận ban đầu của bạn $1sẽ hoạt động).
Eimantas

7
@Eimantas Bạn có muốn giải thích trong một câu trả lời không? Nó không hoạt động đối với tôi và tôi không thể tìm thấy bất kỳ tài liệu nào về nó.
pavon

@Eimantas không có gì về điều này trong ghi chú phát hành mặc dù.
Knu

1
tôi có thể xác nhận rằng tôi có thể chạy các lệnh shell với các đối số mà không cần bất kỳ shenanigans nào trong Git 2.11.
Anarcat

Câu trả lời:


365

Cách rõ ràng nhất là sử dụng hàm shell:

[alias]
    files = "!f() { git diff --name-status \"$1^\" \"$1\"; }; f"

Một bí danh mà không !được coi là lệnh Git; ví dụ commit-all = commit -a.

Với !, nó chạy như một lệnh riêng trong vỏ, cho phép bạn sử dụng phép thuật mạnh hơn như thế này.

CẬP NHẬT
Bởi vì các lệnh được thực thi ở thư mục gốc của kho lưu trữ, bạn có thể sử dụng ${GIT_PREFIX}biến khi tham chiếu đến tên tệp trong các lệnh


8
Cảm ơn, điều này có vẻ chính xác: [bí danh] files = "! F () {echo $ 3 $ 2 $ 1;}; f"; $ git tập tin abc => cba
user400575

1
@ KohányiRóbert: Đó thực sự không phải là một câu hỏi kịch bản shell; đó là một đặc biệt của cấu hình git. Một bí danh mà không !được coi là lệnh Git; ví dụ commit-all = commit -a. Với !, nó chạy như một lệnh riêng trong vỏ, cho phép bạn sử dụng phép thuật mạnh hơn như thế này.
Cascabel

40
Hãy cẩn thận, !sẽ chạy ở thư mục gốc của kho lưu trữ, vì vậy sử dụng các đường dẫn tương đối khi gọi bí danh của bạn sẽ không cho kết quả như bạn mong đợi.
Drealmer

4
@RobertDailey Nó không phá vỡ nó, nó chỉ không thực hiện nó. Xem stackoverflow.com/questions/342969/ trên để biết cách thêm nó.
Cascabel

3
Lưu ý : Điều này không trích dẫn các đối số (nói chung là nguy hiểm). Ngoài ra, một chức năng là không cần thiết. Xem câu trả lời của tôi để giải thích thêm.
Tom Hale

96

Bạn cũng có thể tham khảo shtrực tiếp (thay vì tạo hàm):

[alias]
        files = !sh -c 'git diff --name-status $1^ $1' -

(Lưu ý dấu gạch ngang ở cuối dòng - bạn sẽ cần điều đó.)


8
Nếu bạn đang chia sẻ lệnh, có lẽ bạn muốn sử dụng sh, vì bản thân nó là một vỏ và nó có sẵn trên phần lớn các hệ thống. Sử dụng shell mặc định chỉ hoạt động nếu lệnh hoạt động như được viết cho tất cả các shell.
nomothetis

12
Tôi thích --đến -vì nó là quen thuộc hơn và ít có khả năng vô tình stdin trung bình tại một số điểm. ("Đối số của - tương đương với -" trong bash (1) là không thể kết hợp được)
bsb


5
Ý nghĩa chính xác của kết thúc '-' và nó được ghi lại ở đâu?
Zitrax

5
Lưu ý : Điều này không trích dẫn các đối số (nói chung là nguy hiểm). Tạo một vỏ con (với sh -c) cũng không cần thiết. Xem câu trả lời của tôi cho một sự thay thế.
Tom Hale

81

Bí danh bạn đang tìm kiếm là:

files = "!git diff --name-status \"$1\"^ \"$1\" #"

Với xác thực đối số:

files = "!cd -- \"${GIT_PREFIX:-.}\" && [ x$# != x1 ] && echo commit-ish required >&2 || git diff --name-status \"$1\"^ \"$1\" #"

Cuối cùng# là rất quan trọng - nó ngăn chặn tất cả các đối số do người dùng cung cấp được xử lý bởi trình bao (nó nhận xét chúng).

Lưu ý: gitđặt tất cả các đối số do người dùng cung cấp ở cuối dòng lệnh. Để thấy điều này trong hành động, hãy thử:GIT_TRACE=2 git files a b c d

Các trích dẫn thoát (do lồng nhau) rất quan trọng đối với tên tệp chứa dấu cách hoặc "; rm -rf --no-preserve-root /;)


Đối với các trường hợp đơn giản nhất, đây là câu trả lời đúng, thực sự không cần phải phức tạp bằng cách gói nó trong một hàm hoặc sh -c.
Ed Randall

4
Có, !đã ngụ ý sh -c(hiển thị khi trả trước GIT_TRACE=2), do đó không cần phải chạy một lớp vỏ phụ khác. Những vấn đề bạn nhìn thấy trong các trường hợp phức tạp hơn?
Tom Hale

Điều này có hoạt động nếu bạn muốn đặt đối số mặc định? ví dụ: tôi muốn làm điều này để lấy Github PR : fp = "! 1=${1:-$(git headBranch)}; 2=${2:-up}; git fetch -fu $2 pull/$1/head:$1; git checkout $1; git branch -u $2 #". Điều này hoạt động tuyệt vời mà không có hai tuyên bố đầu tiên, nhưng rơi xuống nếu bạn sử dụng chúng. (Tôi headBranch = symbolic-ref --short HEADcũng có).
gib

2
Làm việc được, nó hoạt động nếu bạn đặt thông số mới, vì vậy điều này là tốt : fp = "! a=${1:-$(git headBranch)}; b=${2:-up}; git fetch -fu $b pull/$a/head:$a; git checkout $a; git branch -u $b #".
gib

Tại sao "báo giá được yêu cầu?
Eugen Konkov

28

Sử dụng GIT_TRACE = 1 được mô tả trên trang git man để xử lý bí danh minh bạch:

$ git config alias.files
!git diff --name-status $1^ $1
$ GIT_TRACE=1 git files 1d49ec0
trace: exec: 'git-files' '1d49ec0'
trace: run_command: 'git-files' '1d49ec0'
trace: run_command: 'git diff --name-status $1^ $1' '1d49ec0'
trace: exec: '/bin/sh' '-c' 'git diff --name-status $1^ $1 "$@"' 'git diff --name-status $1^ $1' '1d49ec0'
trace: built-in: git 'diff' '--name-status' '1d49ec0^' '1d49ec0' '1d49ec0'
trace: run_command: 'less -R'
trace: exec: '/bin/sh' '-c' 'less -R' 'less -R'
MM      TODO

Các lệnh ban đầu của bạn hoạt động với phiên bản git 1.8.3.4 (Eimantas lưu ý điều này đã thay đổi trong 1.8.2.1).

Cả hai tùy chọn sh -c '..' --f() {..}; fxử lý sạch các tham số "$ @" theo các cách khác nhau (xem với GIT_TRACE). Việc thêm "#" vào bí danh cũng sẽ cho phép các tham số vị trí mà không để lại các tham số.


1
cảm ơn đã giải thích: những lệnh đó hoạt động cho tôi về vấn đề ban đầu, làm theo lời khuyên của bạn:files = "!git diff --name-status $1^ $1 #" files = "!git diff --name-status $1^"
user2291758

20

Như đã nêu của Drealmer ở trên :

" Hãy cẩn thận, ! sẽ chạy ở thư mục gốc của kho lưu trữ, vì vậy sử dụng các đường dẫn tương đối khi gọi bí danh của bạn sẽ không cho kết quả như bạn mong đợi. - Drealmer ngày 8 tháng 8 năm 13 lúc 16:28 »

GIT_PREFIX được đặt bởi git vào thư mục con bạn đang ở, bạn có thể phá vỡ điều này bằng cách thay đổi thư mục đầu tiên:

git config --global alias.ls '! cd "$ {GIT_PREFIX: -.}"; ls -al '


Tôi cũng gặp vấn đề với điều này (các lệnh đang được chạy ở thư mục gốc của kho lưu trữ) nhưng giải pháp này dường như không làm gì cả. (Nếu có vấn đề, tôi đang sử dụng OS X.)
waldyrious

Rất tiếc ... bí danh là một bí danh tôi đã thực hiện.
Pierre-Olivier Vares

(kể từ git 1.8.2) git config --set alias.alias = '! git config - bí danh toàn phần. $ 1 "$ 2" '
Pierre-Olivier Vares

Đây là những gì đã kết thúc với tôi: "tiền tố bí danh git của bạn (chạy lệnh shell và cần pwd đúng) với cd ${GIT_PREFIX:-.} &&." (nguồn: stackoverflow.com/a/21929373/266309 )
waldyrious

Hãy trích dẫn điều này. !cd "${GIT_PREFIX:-.}" && ls -al
mirabilos

8

Tôi muốn làm điều này với một bí danh thực hiện điều này:

git checkout $1;
git merge --ff-only $2;
git branch -d $2;

Cuối cùng, tôi đã tạo một tập lệnh shell có tên git-m có nội dung này:

#!/bin/bash -x
set -e

#by naming this git-m and putting it in your PATH, git will be able to run it when you type "git m ..."

if [ "$#" -ne 2 ]
then
  echo "Wrong number of arguments. Should be 2, was $#";
  exit 1;
fi

git checkout $1;
git merge --ff-only $2;
git branch -d $2;

Điều này có lợi ích mà nó là nhiều hơn dễ đọc vì nó trên nhiều dòng. Thêm vào đó tôi thích có thể gọi bash với -xset -e. Bạn có thể có thể làm toàn bộ điều này như một bí danh, nhưng nó sẽ siêu xấu xí và khó duy trì.

Vì tệp được đặt tên git-mnên bạn có thể chạy nó như thế này:git m foo bar


1
Tôi cũng thích điều này nhiều hơn, nhưng tôi chưa thể tìm ra cách sử dụng tự động hoàn thành mà tôi muốn với phương pháp này. Trên các bí danh bạn có thể làm điều này: '!f() { : git branch ; ... }; f'và nó sẽ tự động hoàn thành bí danh như một nhánh siêu tiện dụng.
Hassek

Vâng, tôi nghĩ rằng tôi thích có những thứ không tầm thường được thực hiện dưới dạng các tệp script riêng lẻ trên đường dẫn. Mặt trái là có, bạn mất tự động hoàn thành những thứ như tài liệu tham khảo. Mặc dù vậy, bạn có thể khắc phục điều này bằng cách tự cấu hình tự động hoàn thành. Mặc dù vậy, một lần nữa, tôi thích rằng bạn chỉ cần thả tập lệnh vào một thư mục trên đường dẫn và nó sẽ bắt đầu hoạt động, nhưng để tự động hoàn thành, bạn cần phải 'tải' nó, vì vậy thường là trong .bashrctệp của tôi mà tôi cung cấp. Nhưng tôi không nghĩ rằng tôi thay đổi cách tôi tự động hoàn thành các đối số thành một kịch bản nhiều như chính kịch bản đó và nó chỉ có trong thời gian phát triển.
thecoshman

4

Chỉ va vào một cái gì đó tương tự; hy vọng nó là oK để gửi ghi chú của tôi. Một điều khiến tôi bối rối về gitbí danh với các đối số, có lẽ đến từ git help config(tôi có phiên bản git 1.7.9.5):

Nếu việc mở rộng bí danh được bắt đầu bằng dấu chấm than, nó sẽ được coi là lệnh shell. Ví dụ: định nghĩa "alias.new =! Gitk --all --not ORIG_HEAD", cách gọi "git new" tương đương với việc chạy lệnh shell "gitk --all --not ORIG_HEAD". Lưu ý rằng các lệnh shell sẽ được thực thi từ thư mục cấp cao nhất của kho lưu trữ, có thể không nhất thiết phải là thư mục hiện tại. [...]

Cách tôi nhìn thấy - nếu một bí danh "sẽ được coi là lệnh shell" khi được thêm tiền tố vào dấu chấm than - tại sao tôi cần sử dụng hàm hoặc sh -cvới các đối số; Tại sao không chỉ viết lệnh của tôi như là?

Tôi vẫn không biết câu trả lời - nhưng tôi nghĩ thực sự có một chút khác biệt trong kết quả. Đây là một bài kiểm tra nhỏ - ném cái này vào của bạn .git/confighoặc của bạn ~/.gitconfig:

[alias]
  # ...
  ech = "! echo rem: "
  shech = "! sh -c 'echo rem:' "
  fech = "! f() { echo rem: ; }; f " # must have ; after echo!
  echargs = "! echo 0[[\"$0\"]] 1-\"$1\"/ A-"$@"/ "
  fechargs = "! f() { echo 0[[\"$0\"]] 1-\"$1\"/ A-"$@"/ ; }; f "

Đây là những gì tôi nhận được khi chạy các bí danh:

$ git ech word1 word2
rem: word1 word2

$ git shech word1 word2
rem:

$ git fech word1 word2
rem:

$ git echargs word1 word2
0[[ echo 0[["$0"]] 1-"$1"/ A-$@/ ]] 1-word1/ A-word1 word2/ word1 word2

$ git fechargs word1 word2
0[[ f() { echo 0[["$0"]] 1-"$1"/ A-$@/ ; }; f ]] 1-word1/ A-word1 word2/

... hoặc: khi bạn đang sử dụng lệnh "đơn giản" sau !"nguyên trạng" trong gitbí danh - sau đó gittự động nối thêm danh sách đối số vào lệnh đó! Thực ra, một cách để tránh nó, gọi kịch bản của bạn là một hàm - hoặc là đối số sh -c.

Một điều thú vị khác ở đây (đối với tôi), là trong một tập lệnh shell, người ta thường mong đợi biến tự động $0là tên tệp của tập lệnh. Nhưng đối với một githàm bí danh $0, về cơ bản, đối số là toàn bộ nội dung của chuỗi xác định lệnh đó (như được nhập trong tệp cấu hình).

Đó là lý do tại sao, tôi đoán, nếu bạn tình cờ hiểu sai - trong trường hợp dưới đây, điều đó sẽ thoát khỏi dấu ngoặc kép bên ngoài:

[alias]
  # ...
  fail = ! \"echo 'A' 'B'\"

... - sau đó gitsẽ thất bại với (đối với tôi, ít nhất là) thông điệp hơi khó hiểu:

$ git fail
 "echo 'A' 'B'": 1: echo 'A' 'B': not found
fatal: While expanding alias 'fail': ' "echo 'A' 'B'"': No such file or directory

Tôi nghĩ, vì git"đã thấy" cả một chuỗi chỉ là một đối số !- nó đã cố chạy nó dưới dạng một tệp thực thi; và tương ứng nó không tìm thấy "echo 'A' 'B'"như một tập tin.

Trong mọi trường hợp, trong bối cảnh của git help configtrích dẫn ở trên, tôi suy đoán rằng chính xác hơn để nói một cái gì đó như: " ... lời gọi" git new "tương đương với việc chạy lệnh shell" gitk --all --not ORIG_HEAD $ @ ", trong đó $ @ là các đối số được truyền cho bí danh lệnh git từ dòng lệnh khi chạy. ... ". Tôi nghĩ điều đó cũng sẽ giải thích, tại sao cách tiếp cận "trực tiếp" trong OP không hoạt động với các tham số vị trí.


kiểm tra tốt đẹp. Một cách nhanh chóng để kiểm tra tất cả các khả năng!
albfan

failđang cố chạy một lệnh gọi là "echo 'A' 'B" (tức là dài 10 ký tự). Cùng một lỗi từ sh -c "'echo a b'"và cùng một nguyên nhân, quá nhiều lớp trích dẫn
bsb
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.