Tôi có thể lưu trữ thư mục .git bên ngoài các tệp tôi muốn theo dõi không?


147

Tôi có một ý tưởng khác thường là sử dụng git làm hệ thống dự phòng. Vì vậy, hãy nói rằng tôi có một thư mục ./backup/myfiles và tôi muốn sao lưu nó bằng git. Để giữ mọi thứ sạch sẽ, tôi không muốn có một thư mục .git trong thư mục myfiles, vì vậy tôi nghĩ rằng tôi có thể tạo ./backup/git numpose / myfiles. Từ việc xem các tài liệu git, tôi đã thử làm điều này:

$ cd backup/myfiles
$ mkdir ../git_repos/myfiles
$ git --git-dir=../git_repos/myfiles init
Initialized empty Git repository in backup/git_repos/myfiles/
$ git --git-dir="../git_repos/myfiles/" add foo
fatal: pathspec 'foo' did not match any files

Bạn có thể thấy thông báo lỗi tôi nhận được ở đó. Tôi đang làm gì sai?


9
Cũng như ý tưởng sao lưu của bạn, điều này cũng có thể được sử dụng để giữ "dotfiles" (.bashrc, .vimrc, v.v.) của bạn trong thư mục chính trong khi giữ thư mục .git ở nơi khác.
Philip

6
Câu trả lời thẳng thắn nhất: stackoverflow.com/a/19548676/170352 (bị chôn vùi vì những câu chuyện cũ)
Brandon Bertelsen

1
Trong trường hợp đó bạn không có quyền sửa hoặc không muốn thực hiện bất kỳ thay đổi thư mục làm việc (như thêm .git / vv), này trả lời dưới đây của Leo (cũng bị chôn vùi bởi upvotes cũ) là tốt nhất.
KobeJohn

1
@Philip, trừ khi kho lưu trữ dotfiles của bạn cũng chứa các mô đun con Git. Git không hỗ trợ các mô đun con kết hợp với cây công việc bên ngoài.
maxschlepzig

Câu trả lời:


101
git --git-dir=../repo --work-tree=. add foo

Điều này sẽ làm những gì bạn muốn nhưng rõ ràng sẽ hút khi bạn phải chỉ định nó với mỗi lệnh git bạn từng sử dụng.

Bạn có thể xuất GIT_WORK_TREE=.GIT_DIR=../backupGit sẽ chọn chúng trên mỗi lệnh. Điều đó sẽ chỉ thoải mái cho phép bạn làm việc trong một kho lưu trữ trên mỗi vỏ, mặc dù.

Tôi muốn đề xuất symlinking thư mục .git đến một nơi khác hoặc tạo symlink đến thư mục .git từ thư mục sao lưu chính của bạn.


1
Bạn có thể lưu trữ tương tự mà không chỉ định git-dir và cây công việc trong mỗi lệnh và không có bất kỳ liên kết tượng trưng nào. Xem câu trả lời của tôi.
niks

Nhược điểm của liên kết tượng trưng là nó tồn tại trong cây công việc và nếu một số quy trình khác xóa sạch cây công việc, thì bạn đã mất liên kết tượng trưng
Jeff

Hơn nữa, nếu OP không muốn có thư mục con .git trong cây công việc của mình, tại sao anh ta lại muốn có một liên kết tượng trưng?
Jeff

@Jeff: cho một sự đánh đổi. (Trong trường hợp dự phòng của anh ấy, xóa sạch cây công việc của anh ấy có lẽ không phải là mối quan tâm lớn hơn đối với anh ấy hơn là xóa sạch bất kỳ thư mục nào khác (như chính repo).)
Sz.

1
Tôi đang sử dụng điều này cùng với direnv cho ghi chú của tôi. Cây làm việc của tôi nằm trong một thư mục trong Dropbox và thư mục git của tôi ở đâu đó bên ngoài. Bằng cách này, tôi có thể dễ dàng thay đổi trên tất cả các máy tính nhưng vẫn có thể kiểm tra những gì đã thay đổi và chỉ cam kết khi có gì đó quan trọng đã thay đổi. Cảm ơn
Paulo Phagula

170

Bạn chỉ cần đảm bảo rằng kho lưu trữ biết cây công việc ở đâu và ngược lại.

Để cho kho lưu trữ biết cây công việc ở đâu, hãy đặt giá trị cấu hình core.worktree. Để cho cây công việc biết thư mục git của nó ở đâu, hãy thêm một tệp có tên .git (không phải là thư mục!) Và thêm một dòng như

gitdir: /path/to/repo.git

Vì git 1.7.5, lệnh init đã học thêm một tùy chọn cho việc này.

Bạn có thể khởi tạo một kho lưu trữ riêng biệt mới với

git init --separate-git-dir /path/to/repo.git

Điều này sẽ khởi tạo kho git trong thư mục riêng và thêm tệp .git trong thư mục hiện tại, đây là thư mục làm việc của kho lưu trữ mới.

Trước đây đến 1.7.5, bạn phải sử dụng các tham số hơi khác nhau và tự thêm tệp .git.

Để khởi tạo một kho lưu trữ riêng biệt, lệnh sau liên kết cây công việc với kho lưu trữ:

git --git-dir=/path/to/repo.git --work-tree=. init && echo "gitdir: /path/to/repo.git" > .git

Thư mục hiện tại của bạn sẽ là cây làm việc và git sẽ sử dụng kho lưu trữ tại /path/to/repo.git. Lệnh init sẽ tự động đặt core.worktreegiá trị như được chỉ định với --git-dirtham số.

Bạn thậm chí có thể thêm một bí danh cho điều này:

[alias]
    initexternal = !"f() { git --work-tree=. --git-dir=\"$1\" init && echo \"gitdir: $1\" >> .git; }; f"

Sử dụng kiểm soát phiên bản git trên thư mục làm việc chỉ đọc

Với kiến ​​thức ở trên, bạn thậm chí có thể thiết lập kiểm soát phiên bản git cho một thư mục làm việc mà không có quyền ghi. Nếu bạn sử dụng --git-dirtrên mọi lệnh git hoặc thực thi mọi lệnh từ trong kho lưu trữ (thay vì thư mục làm việc), bạn có thể bỏ tệp .git và do đó không cần tạo bất kỳ tệp nào trong thư mục làm việc. Xem thêm Leos trả lời


7
Bạn cũng có thể làm điều này với một repo hiện có: di chuyển thư mục .git đến bất cứ nơi nào bạn muốn, thêm tệp .git để trỏ đến nó, và sau đó bạn có thể tiếp tục sử dụng repo như bình thường
joachim

Lưu ý rằng bạn chỉ có thể phát lệnh git từ thư mục gốc của repo. Đi vào thư mục con nhầm lẫn nó! (Điều này xảy ra cho dù giá trị đã cho của gitdir là tương đối hay tuyệt đối.)
joachim

2
Cách khắc phục cho vấn đề này là chỉ định 'core.worktree' trong tệp cấu hình git thực tế, tức là tệp trong thư mục bạn trỏ đến .git.
joachim

2
Vâng, đó là những gì tôi mô tả trong câu thứ hai của câu trả lời của tôi. Giá trị cấu hình core.worktreetất nhiên được lưu trữ trong tệp cấu hình của thư mục .git, trong đó tệp .git trỏ đến.
niks

1
Tôi tìm thấy khi tôi sử dụng các hướng dẫn này, repo được tạo thành một kho lưu trữ trần và nó báo lỗi fatal: core.worktree and core.bare do not make sense. Có vẻ như chỉ thay đổi cấu hình để nó không giải quyết được điều đó.
Steven Lu

62

Các --separate-git-dirlựa chọn cho git init(và git clone) có thể được sử dụng để thực hiện điều này trên phiên bản của tôi về git ( 1.7.11.3). Tùy chọn tách kho lưu trữ git khỏi cây công việc và tạo ra một liên kết tượng trưng git bất khả tri của hệ thống tập tin (dưới dạng một tệp có tên .git) trong thư mục gốc của cây công việc. Tôi nghĩ rằng kết quả là giống hệt với câu trả lời của niks .

git init --separate-git-dir path/to/repo.git path/to/worktree

2
+1 Sử dụng tùy chọn dòng lệnh cho initbản thân trông rõ ràng và gọn gàng hơn
goncalopp

trong windows, repo.gitđược tạo với tập thuộc tính hiden của nó. Tôi sau đó thay đổi nó bằng tay. Bạn có tình cờ biết điều này có an toàn không?
PA.

+1 Có git đã nghiêng tùy chọn dòng lệnh này trong phiên bản 1.7.5, không có sẵn sau đó (nếu tôi nhớ đúng). Tôi đã cập nhật câu trả lời của mình để đề nghị sử dụng tham số này.
niks

25

Tôi thấy đơn giản hơn để đảo ngược --work-treevà các --git-dirthư mục được sử dụng trong câu trả lời của niks:

$ cd read_only_repos
$ git --work-tree=/some/readonly/location/foo/ --git-dir=foo init
$ cd foo
$ git status
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        .file_foo
        bar
        ...

Cách tiếp cận này có hai ưu điểm:

  • Nó loại bỏ sự cần thiết phải có bất kỳ tùy chọn dòng lệnh hoặc .gittập tin. Bạn chỉ cần hoạt động bình thường từ bên trong thư mục gốc.
  • Nó cho phép bạn phiên bản một hệ thống tập tin ngay cả khi bạn không sở hữu nó. Git sẽ chỉ ghi vào vị trí kho lưu trữ.

Nhắc nhở duy nhất tôi gặp phải là thay vì sử dụng một .gitignoretập tin, bạn chỉnh sửa info/exclude.

Sau đó, bạn có thể sử dụng kho lưu trữ read_only_repos/foonhư một điều khiển từ xa trong kho của riêng bạn ngay cả khi các tệp gốc không nằm dưới sự kiểm soát phiên bản.


Vâng, đây chính xác là cùng một lệnh. Sự khác biệt duy nhất mà tôi thấy là bạn đã hoán đổi thứ tự của các đối số --work-tree và --git-dir. Và tất nhiên, bạn không tạo tệp .git trong thư mục làm việc vì bạn không có quyền ghi vào nó. Tuy nhiên, sử dụng kiểm soát phiên bản cho một thư mục mà không có quyền ghi vào nó là một trường hợp sử dụng tốt. :-)
niks

3
Bạn đã nhận nó. Chìa khóa đang tạo repo bên ngoài thư mục làm việc.
Leo

4
Tôi thích điều này - nó cho phép tôi sử dụng git trên các thư mục tôi đang chia sẻ với Dropbox, mà không cần những người tham gia khác biết rằng git đang được sử dụng.
Quentin Stafford-Fraser

19

Việc đặt tên một thư mục là một kho lưu trữ git có cây làm việc ở một nơi khác thường có phần mở rộng '.git', giống như một kho lưu trữ trần.

mkdir ../git_repos/myfiles.git

Nếu bạn đã cung cấp --work-treetùy chọn tại thời điểm init thì điều này sẽ tự động thiết lập core.worktreebiến cấu hình có nghĩa là git sẽ biết nơi tìm cây làm việc một khi bạn chỉ định thư mục git.

git --git-dir=../git_repos/myfiles.git --work-tree=. init

Nhưng bạn có thể đặt biến này sau khi thực tế là tốt.

git --git-dir=../git_repos/myfiles.git config core.worktree "$(pwd)"

Khi bạn đã thực hiện điều này, lệnh add sẽ hoạt động như mong đợi.

git --git-dir=../git_repos/myfiles.git add foo

Tôi đã tìm thấy nếu bạn cd vào ../git_Vpose/myfiles.git, thay vì ở trong cây công việc thực, 'git add foo' sẽ chỉ hoạt động và bạn không cần chỉ định --git-dir tất cả thời gian.
Steve Folly

1
Đó là sự thật, nhưng tôi nghĩ rằng hầu hết mọi người có xu hướng làm việc trong cây làm việc của họ hơn là kho lưu trữ của họ. Tất nhiên, nếu bạn đang sử dụng một cây làm việc tách rời, có lẽ bạn đang làm điều gì đó 'đặc biệt' và có thể đang sử dụng một số macro để trợ giúp.
CB Bailey

6

Sử dụng gitbên trong repo:

cd ./backup/git_repos/myfiles
git init --bare
git config core.worktree ../myfiles
git config core.bare false

Từ giờ trở đi, bạn có thể sử dụng gitbên trong ./backup/git_repos/myfilesthư mục mà không cần đặt bất kỳ biến môi trường hoặc tham số bổ sung nào.


Đây có vẻ là câu trả lời tốt nhất, nhưng tôi nhận được thông báo warning: core.bare and core.worktree do not make sensecó nghĩa là nó không hoạt động?
hazrpg

1
Tôi vẫn nghĩ là công việc, nhưng nó phàn nàn về việc để trần khi đặt bàn làm việc. Đó là lý do tại sao tôi đang thiết core.baređể falsesau đó.
To1ne

Ah! Điều đó có ý nghĩa hơn bây giờ. Cảm ơn vì điều đó.
hazrpg

1

Bạn có thể tạo một tập lệnh "gật đầu" (Không có GIT) với đôi khi như

#!/bin/sh
gits=/usr/local/gits
    x=`pwd`
    testdir() {( cd $1; pwd; )}
    while [ "$x" != "/" ]; do
      y=`echo $x|sed -e "s/\//__/g"`
      if ([ -d "$gits/$y" ]); then
        export GIT_DIR="$gits/$y"
        export GIT_WORK_TREE="$x"
        if ([ "$1" = "nodinit" ]); then
          mkdir -p "$GIT_DIR"
          git init --bare; exit $?
        elif ([ "$1" = "shell" ]); then
          bash; exit $?
        else
          exec git "$@"
        fi
      fi
      x=`testdir "$x/.."`
    done

Bạn có thể gọi gật đầu thay cho git và nó sẽ đặt các biến khi cần thiết bằng cách tìm kiếm một repo git. Ví dụ: bạn có repo (trần) trong / usr / local / gits / __ home__foo_wibble và bạn đang ở trong / home / foo / wibble / một thì nó sẽ tìm đúng thư mục làm việc (/ home / foo / wibbled) và repo .

Ồ, bạn cũng có thể sử dụng "shell gậtgit" để lấy shell với bộ vars chính xác để bạn có thể sử dụng các lệnh git cũ đơn giản.


0

Giả sử myfilesthư mục của bạn đã tồn tại và có một số nội dung, bạn có thể sống với điều này:

cd ~/backup
git init
git add myfiles

Các .gitthư mục sẽ được trong backup, không phải trong myfiles.


Mặc dù điều đó sẽ khắc phục những gì tôi muốn, tôi chỉ muốn lưu trữ thư mục myfiles dưới git, và không có gì khác.
Rory

Bạn có thể giữ một lựa chọn các tệp bạn muốn gittheo dõi bằng cách sử dụng .gitignoretệp. Nếu bạn thêm *!myfilesvào nó, chỉ thư mục đó sẽ được theo dõi. Nhưng nếu bạn muốn có một repo riêng cho một thư mục khác, bạn sẽ gặp vấn đề ...
To1ne

0

Tôi tạo các kịch bản trông giống như

~ / bin / git-slash:

#!/usr/bin/sh

export GIT_DIR=/home/Version-Control/cygwin-root.git/
export GIT_WORK_TREE=/

git --git-dir=$GIT_DIR --work-tree=$GIT_WORK_TREE "$@"

exit $?

Việc sử dụng --git_dir = $ GIT_DIR là không cần thiết, nhưng nhắc nhở tôi rằng tôi cũng có thể đặt các biến môi trường bên ngoài tập lệnh.

Ví dụ trên là để theo dõi các thay đổi cục bộ đối với các tệp hệ thống cygwin.

Có thể tạo một kịch bản như vậy cho bất kỳ dự án lớn nào cần điều này - nhưng / không có /.git là mục đích sử dụng chính của tôi.

Ở trên là đủ nhỏ để tạo một bí danh vỏ hoặc chức năng, nếu bạn loại bỏ sự dư thừa.

Nếu tôi làm điều này thường xuyên đủ, tôi sẽ hồi sinh không gian làm việc để ánh xạ kho lưu trữ của

"Boxes, Links, and Parallel Trees: Elements of a Configuration Management System", 
in Workshop Proceedings of the Software Management Conference. 1989.

có đối tác hiện đại gần nhất là ánh xạ hoặc quan điểm của Perforce , hỗ trợ kiểm tra một phần cũng như không bố trí không gian làm việc và repo.

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.