- (cond ((file-directory-p (expand-file-name ".bzr/branch" dir))
- (if (eq external 'force)
- (emacs-bzr-version-bzr dir)
- (let (file loc rev)
- (cond ((file-readable-p
- (setq file (expand-file-name
- ".bzr/branch/last-revision" dir)))
- (with-temp-buffer
- (insert-file-contents file)
- (goto-char (point-max))
- (if (looking-back "\n")
- (delete-char -1))
- (buffer-string)))
- ;; OK, no last-revision. Is it a lightweight checkout?
- ((file-readable-p
- (setq file (expand-file-name ".bzr/branch/location" dir)))
- (setq rev (emacs-bzr-version-dirstate dir))
- ;; If parent branch is local, try looking there for the rev.
- ;; Note: there is no guarantee that the parent branch's rev
- ;; corresponds to this branch. This branch could have
- ;; been made with a specific -r revno argument, or the
- ;; parent could have been updated since this branch was
- ;; created.
- ;; To try and detect this, we check the dirstate revids
- ;; to see if they match.
- (if (and (setq loc (with-temp-buffer
- (insert-file-contents file)
- (if (looking-at "file://\\(.*\\)")
- (match-string 1))))
- (equal rev (emacs-bzr-version-dirstate loc)))
- (emacs-repository-get-version loc)
- ;; If parent does not match, the best we can do without
- ;; calling external commands is to use the dirstate rev.
- rev))
- (external
- (emacs-bzr-version-bzr dir))))))
- ((file-directory-p (expand-file-name ".git" dir))
- (message "Waiting for git...")
- (with-temp-buffer
- (let ((default-directory (file-name-as-directory dir)))
- (and (eq 0
- (condition-case nil
- (call-process "git" nil '(t nil) nil "rev-parse"
- "HEAD")
- (error nil)))
- (not (zerop (buffer-size)))
- (replace-regexp-in-string "\n" "" (buffer-string))))))))
+ (let* ((base-dir (expand-file-name ".git" dir))
+ (in-main-worktree (file-directory-p base-dir))
+ (in-linked-worktree nil)
+ sub-dir)
+ ;; If the sources are in a linked worktree, .git is a file that points to
+ ;; the location of the main worktree and the repo's administrative files.
+ (when (and (not in-main-worktree)
+ (file-regular-p base-dir)
+ (file-readable-p base-dir))
+ (with-temp-buffer
+ (insert-file-contents base-dir)
+ (when (looking-at "gitdir: \\(.*\.git\\)\\(.*\\)$")
+ (setq base-dir (match-string 1)
+ sub-dir (concat base-dir (match-string 2))
+ in-linked-worktree t))))
+ ;; We've found a worktree, either main or linked.
+ (when (or in-main-worktree in-linked-worktree)
+ (if external
+ (emacs-repository-version-git dir)
+ (or (if in-linked-worktree
+ (emacs-repository--version-git-1
+ (expand-file-name "HEAD" sub-dir) base-dir)
+ (let ((files '("HEAD" "refs/heads/master"))
+ file rev)
+ (while (and (not rev)
+ (setq file (car files)))
+ (setq file (expand-file-name file base-dir)
+ files (cdr files)
+ rev (emacs-repository--version-git-1 file base-dir)))
+ rev))
+ ;; AFAICS this doesn't work during dumping (bug#20799).
+ (emacs-repository-version-git dir))))))