与 GNU Stow 的“--adopt”选项相反?

与 GNU Stow 的“--adopt”选项相反?

我在用着GNU 斯托按照以下方式管理我的点文件本指南。这对于机器上没有预先存在的点文件的情况非常有效。例如,如果没有文件~/.config/foo.cfg,则以下内容可以正常工作:

~/.dotfiles$ mkdir -p foo/.config
~/.dotfiles$ echo My config > foo/.config/foo.cfg
~/.dotfiles$ stow foo
~/.dotfiles$ ls -l ~/.config
lrwxrwxrwx 1 user group 21 Dec  6 19:03 ~/.config -> .dotfiles/foo/.config

~/.config/foo.cfg如果已经存在,它就变得不那么简单:

~/.dotfiles$ stow foo
WARNING! stowing bar would cause conflicts:
  * existing target is neither a link nor a directory: foo.cfg
All operations aborted.

到目前为止,我能找到的唯一解决方案是手动删除~/.config/foo.cfg并重新运行stow foo.当向可能有数十个预先存在的 .dot 文件的新计算机配置 stow 存储库时,这是非常尴尬的,并且基本上违背了使用 stow 管理点文件的目的。

斯托有--adopt选择权。运行的stow --adopt foo效果是用计算机上foo预先存在的文件替换存储的文件,然后创建符号链接。foo我正在寻找的是达到相反效果的方法;将计算机的 .dotfiles 替换为存储版本的符号链接,以便可以使用 Git 存储库中的存储点文件来配置新计算机。

这似乎是使用 Stow 管理点文件的一个明显要求,我觉得我错过了一些东西和/或问题已经解决了。

有任何想法吗?

答案1

我遇到了同样的限制,并且找到了一个与该--adopt选项配合良好的工作流程。如中所述存放文档

...它允许目标树中的文件(其内容可能与 stow 包的安装映像中的等效版本不同)被采用到包中,然后通过在 stow 包内运行“git diff ...”之类的内容进行比较,最后要么保留(例如通过“git commit ...”)或丢弃(“git checkout HEAD ...”)。

我的工作流程:

  1. stow使用该选项运行--adopt
  2. 使用 . 将“采用的”文件与我的存储库中最初的文件进行比较git diff
  3. 使用 放弃“已采用”文件引入的所有更改git reset --hard,将整个目录恢复到上次提交的状态。

例子:

# Running from inside .dotfiles repository
❯ tree . -a
.
├── bash
│   ├── .bashrc
│   └── .xprofile

# Stow bash folder as usual and note conflicts (.bashrc in this case)
❯ stow bash
WARNING! stowing bash would cause conflicts:
  * existing target is neither a link nor a directory: .bashrc
All operations aborted.
e conflicts

# Rerun Stow with --adopt flag to place conflicting files in .dotfiles repo (no warnings)
❯ stow bash --adopt

# Use git diff to compare adopted and committed file
❯ git diff
diff --git a/bash/.bashrc b/bash/.bashrc
index cbd6843..0ac2879 100644
--- a/bash/.bashrc
+++ b/bash/.bashrc
@@ -1,121 +1 @@
... Line changes are listed ...

# Discard adopted file and revert back to contents as per last commit
❯ git reset --hard

# Done

我是 dotfiles 和 Stow 的新手,所以我可能缺少一些限制。到目前为止我对结果很满意。

答案2

我遇到了同样的问题。我个人使用 Ansible 来自动化我的所有 GNU Stow 命令。虽然 Ansible 脚本可能并不完全符合您的需求,但我的方法可能会帮助您探索不同的选项;您可以在 bash 中编写类似的脚本,可以通过更改下面写的我的 Ansible 剧本中的 shell 命令来实现。

我的 dotfile 文件夹的结构如下:“~/dotfiles/home/”包含子文件夹名称,如“bash”和“zsh”。在此代码片段中,dotfile_packages = "~/dotfiles/home/"

请记住,这是一种不安全的方法,因为您会在无人看管的情况下删除大量文件。

  - name: Find all dotfiles subfolders
    find:
      paths: "{{ dotfile_packages }}"
      file_type: directory
      recurse: no
    register: dotfile_folders

  - name: Get list of dotfiles to check for GNU Stow conflicts
    shell: find ./home/{{ item }} \( -type f -o -type l \) | sed 's/.\/home\/{{ item }}\///g'
    args:
      chdir: "{{ repo_dir }}"
    register: conflict_files
    with_items: "{{ dotfile_folders.files | map(attribute='path') | list | map('basename') }}"

  - name: Show list of files to be checked for GNU Stow conflicts
    debug:
      msg: "{{ item }}" 
    with_items: "{{ conflict_files.results | map(attribute='stdout_lines') | list | flatten }}"

  # If we don't unstow first, the delete operation erases any previously stowed dotfile sources.
  # Ignoring errors because sometimes unstow will fail to finish because OS added some untracked files.
  - name: Unstow all packages deleting conflict files.
    shell: stow -D -d {{ dotfile_packages }} -t ~/ {{ item }}
    with_items: "{{ dotfile_folders.files | map(attribute='path') | list | map('basename') }}"
    ignore_errors: yes

  - name: Delete conflicting files
    shell: rm -rf ~/{{ item }}
    with_items: "{{ conflict_files.results | map(attribute='stdout_lines') | list | flatten }}"

  - name: Symlink dotfiles
    shell: stow -d {{ dotfile_packages }} -t ~/ {{ item }}
    with_items: "{{ dotfile_folders.files | map(attribute='path') | list | map('basename') }}"

您可以在此处查看我的点文件中使用的此代码片段。

答案3

我通过将 stow 用法包装在生成文件(检查备份目标)

# List of packages to manage with stow
PACKAGES ?= $(filter-out .git .github, $(wildcard */))

# Directory where stow will look for packages. Default is current directory
DIR ?= $$(pwd)

# Default location where stow will create symbolic links
TARGET ?= ${HOME}

IGNORE ?= \.DS_Store

# Stow command to create links
STOW_CMD = stow \
    --dir="${DIR}" \
    --target="${TARGET}" \
    --ignore="${IGNORE}" \
    --ignore="\.DS_Store" \
    --ignore=".*\.template" \
    --no-folding \
    --verbose

# Function to backup existing files for a specific package if they exist
define backup_if_exists
    checks=$$(${STOW_CMD} --no --verbose ${1} 2>&1 | \
        egrep '\* existing target is ' | \
        sed 's/  \* existing target is neither a link nor a directory: //'); \
    for file in $$checks; do \
        filepath=${TARGET}/$$file; \
        backup_suffix="backup-$$(date -u +%Y%m%d%H%M%S)"; \
        echo "Creating backup $$filepath.$$backup_suffix"; \
        mv -h "$$filepath" "$$filepath.$$backup_suffix"; \
    done
endef

# Default rule to create symbolic links for all packages
all: stow

# Rule to backup existing configurations
backup:
    @echo "Checking for existing files to backup..."
    @$(foreach package,$(PACKAGES), \
        $(call backup_if_exists,$(package));)

# Rule to link configurations using stow
stow: backup
    @echo "Applying stow for packages..."
    @$(foreach package,${PACKAGES}, \
        $(STOW_CMD) ${package};)

# Rule to remove symbolic links
unstow:
    @echo "Removing stow links for packages..."
    @$(foreach package,$(PACKAGES), \
        $(STOW_CMD) -D $(package);)

# Rule to reapply symbolic links
restow: backup unstow stow

# Rule to display help
help:
    @echo ""
    @echo "\033[1mUSAGE\033[0m"
    @echo ""
    @echo "  make [target]"
    @echo ""
    @echo "\033[1mTARGETS\033[0m"
    @echo ""
    @echo "  stow    - Create symlinks for all packages (default)"
    @echo "  restow  - Reapply symlinks for all packages"
    @echo "  unstow  - Remove symlinks for all packages (\033[31mcaution\033[0m)"
    @echo "  help    - Show this help message"
    @echo ""

.PHONY: all backup stow unstow restow help

这个 Makefile 是做什么的?

  1. 首次以检查模式启动收起
  2. 列出已经存在的项目
  3. 备份文件
  4. 发射收起
USAGE

  make [target]

TARGETS

  stow    - Create symlinks for all packages (default)
  restow  - Reapply symlinks for all packages
  unstow  - Remove symlinks for all packages (caution)
  help    - Show this help message

答案4

我遇到过同样的问题。这是一个简单的解决方案,假设您正在尝试stow config

stow config
# WARNING! stowing config would cause conflicts:
# ...
# All operations aborted.
rsync -a config/ config.bak/ # create a backup; this may not be exactly the right rsync syntax
stow --adopt config.bak      # should take ownership of all existing files
stow -D config.bak           # remove all the symlinks just created
stow config                  # should now work fine
rm -rf config.bak

相关内容